说在前面

M↓写的第一篇题解,欢迎提出意见.

题目描述

瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这些木棍连在一起拼成一条线,并且使得木棍与木棍相接触的两端颜色都是相同的,给出每根木棍两端的颜色,请问是否存在满足要求的排列方式。

例如,如果只有 \(2\) 根木棍,第一根两端的颜色分别为 red, blue,第二根两端的颜色分别为 red, yellow,那么 blue---red | red----yellow 便是一种满足要求的排列方式。

输入格式

输入有若干行,每行包括两个单词,表示一根木棍两端的颜色,单词由小写字母组成,且单词长度不会超过 \(10\) 个字母,最多有 \(250000\) 根木棍。

输出格式

如果木棒能够按要求排列,输出 Possible,否则输出 Impossible

输入输出样例

输入 #1

blue red
red violet
cyan blue
blue magenta
magenta cyan

输出 #1

Possible

分析

一根木棒就相当于一条边,木棒两边的颜色就是这条边所连的点,所以此题就是问一张图是否存在欧拉路。

欧拉路的判定很简单——所有点都连通(并查集),最多两个点的度为奇数(一个数组就可以搞定)。

那么这道题之所以是蓝题,是因为它对时间要求很严格——最多2.5e6个木棒,以及读入的字符串的处理。

字符串的处理

这里最最最快的方式是用\(trie\)。

\(trie\)中每个节点都有两个元素,\(num\)标记和\(26\)个指针,这里我们用数组模拟指针:

  1. 设\(0\)是根节点,实际上不代表任何的字母
  2. 对于要加入的每一个字符串,逐位考虑
  3. 如果当前节点没有str[i]这个子节点的话就新建一个节点为子节点
  4. 跳转到这个子节点,判断下一位
  5. 重复3、4步骤
  6. 如果最终的节点没有被分配一个编号的话,那么这个就新建一个编号给这个终节点

这样每一个字符串都有了唯一的编号,且编号是连续的,方便开数组等后续操作。

这就完成了trie的部分——字符串到正整数的映射。

struct Trie
{
int son[26],num;
}trie[2000010];
int n,trie_cnt;
int insert(string str)
{
int now=0;
for(int i=0;i<str.size();i++)
{
if(!trie[now].son[str[i]-'a']) trie[now].son[str[i]-'a']=++trie_cnt;
now=trie[now].son[str[i]-'a'];
}
if(!trie[now].num) trie[now].num=++n;
return trie[now].num;
}

可能有人会问为什么不用\(map\)?

因为\(map\)每次插入是\(logn\)的,而\(trie\)每次插入与字符串的长度有关(看作\(O(1)\)就好),题目也说了每个单词不超过\(10\)个字母。

当然也可以用\(unordered_map\)(需要C++11!),不会\(STL\)的同学可以用\(hash\)(这个还是有点慢)。

所以这里最优的就是\(trie\)啦!

判断欧拉路

欧拉路有个经典的故事——七桥问题,相信你应该耳熟能详了。

即:经过每条边正好一次,能不能把所有边都走一遍?

可以证明,只要整个图是连通的,且有奇数度的点不超过两个,那么就存在欧拉路!

  • 度的统计只需要在读入木棒的时候标记一下即可。

  • 判断连通图用并查集

读入

while(cin>>str)
{
x=insert(str);
cin>>str;
y=insert(str);
merge(x,y);
degree[x]++;
degree[y]++;
}

判断

判断这里我用了点小技巧,同时判断度和并查集。

  • 如果有相邻的两项的祖先是不同的,那么这肯定不是连通图,给flag加上一个大数字。
  • 如果这点的度是奇数,那么flag+1就好。
  • 最后判断flag,大于2说明奇度点多了或者图不连通,即不可能有欧拉路,反正则存在。
int flag=(degree[1]&1);
for(int i=2;i<=n;i++)
{
if(getf(i)!=getf(i-1)) flag+=10;
if(degree[i]&1) flag++;
}
if(flag>2) cout<<"Impossible"<<endl;
else cout<<"Possible"<<endl;

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#define re register
#define debug printf("Now is %d\n",__LINE__);
using namespace std; template<class T>inline void read(T&x)
{
char ch=getchar();
while(!isdigit(ch))ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
}
inline int read()
{
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do{G[++g]=x%10;x/=10;}while(x);
for(re int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
} struct Trie
{
int son[26],num;
}trie[2000010];
int n,trie_cnt;
int insert(string str)
{
int now=0;
for(int i=0;i<str.size();i++)
{
if(!trie[now].son[str[i]-'a']) trie[now].son[str[i]-'a']=++trie_cnt;
now=trie[now].son[str[i]-'a'];
}
if(!trie[now].num) trie[now].num=++n;
return trie[now].num;
}
int f[500010];
int getf(int x)
{
while(x!=f[x]) x=f[x];
return x;
}
void merge(int x,int y)
{
x=getf(x);
y=getf(y);
f[x]=y;
}
int degree[500010];
int main()
{
string str;
int x,y;
for(int i=1;i<=500000;i++) f[i]=i;
while(cin>>str)
{
x=insert(str);
cin>>str;
y=insert(str);
merge(x,y);
degree[x]++;
degree[y]++;
}
int flag=(degree[1]&1);
for(int i=2;i<=n;i++)
{
if(getf(i)!=getf(i-1)) flag+=10;
if(degree[i]&1) flag++;
}
if(flag>2) cout<<"Impossible"<<endl;
else cout<<"Possible"<<endl;
return 0;
}

注意

在洛谷上提交的话,如果你\(#2\)无法通过,请注意数组大小问题:

最多有\(2.5e6\)根木棒,意味着最多有\(5e6\)种单词,所以数组要开到\(5e6\),而\(trie\)数组越大越好。

经过我的非精确计算,类似于线段树,每一层新建分支\(26\),最多\(10\)层,(最多\(141,167,095,653,376\)个叶子节点),而题目中有单词数量不超过\(2.5e6\),\(26^4=456976\),应该开到最多\(26+676+17576+2500000≈2,518,278\)即可。(这个是乱算的)

疑惑

如果出现,有两根相同的木棒怎么办?题目中并没有否认这种情况,但是不这样判断的话也过了啊……奇怪啊。

如果以后这道题修改或者加强了,请来踢我一脚(

洛谷P1333 瑞瑞的木棍 字符串 最短路的更多相关文章

  1. 洛谷P1333 瑞瑞的木棍(欧拉回路)

    题目描述 瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这些木棍连在一起拼成一条线,并且使得木棍与木棍相接触的两端颜色都是相同的,给出每根木棍两端的颜色,请问 ...

  2. 洛谷 P4036 [JSOI2008]火星人(splay+字符串hash)

    题面 洛谷 题解 首先,我们知道求最长公共前缀可以用二分答案+hash来求 因为有修改操作, 考虑将整个字符串的hash值放入splay中 接着就是splay的基本操作了 Code #include& ...

  3. 洛谷 P3263 [JLOI2015]有意义的字符串

    洛谷 首先,看到\((\frac{(b+\sqrt{d})}{2})^n\),很快能够想到一元二次方程的解\(\frac{-b\pm\sqrt{\Delta}}{2a}\). 所以可以推出,\(\fr ...

  4. 洛谷 P1308 统计单词数【字符串+模拟】

    P1308 统计单词数 题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定 ...

  5. 洛谷P3234 抄卡组 [HNOI2014] 字符串hash

    正解:字符串hash 解题报告: 传送门! 字符串hash是字符串匹配中很常见的一个方法,原理也很好懂,这里就不做太多阐述辣有时间放到hash笔记里面去QAQ 题意不说了挺好理解的,自带一句话概括好评 ...

  6. 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]

    题目传送门 A Horrible Poem 题目描述 Bytie boy has to learn a fragment of a certain poem by heart. The poem, f ...

  7. 洛谷 P1308 统计单词数【字符串处理】

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给 ...

  8. 洛谷P1781 宇宙总统【排序+字符串】

    地球历公元6036年,全宇宙准备竞选一个最贤能的人当总统,共有n个非凡拔尖的人竞选总统,现在票数已经统计完毕,请你算出谁能够当上总统. 输入输出格式 输入格式: president.in 第一行为一个 ...

  9. 洛谷P1603——斯诺登的密码(字符串处理)

    https://www.luogu.org/problem/show?pid=1603#sub 题目描述 2013年X月X日,俄罗斯办理了斯诺登的护照,于是他混迹于一架开往委内瑞拉的飞机.但是,这件事 ...

  10. 洛谷P5292 [HNOI2019]校园旅行(二分图+最短路)

    题面 传送门 题解 如果暴力的话,我们可以把所有的二元组全都扔进一个队列里,然后每次往两边更新同色点,这样的话复杂度是\(O(m^2)\) 怎么优化呢? 对于一个同色联通块,如果它是一个二分图,我们只 ...

随机推荐

  1. HarmonyOS SDK让小红书鸿蒙用户尽享原生相机的拍摄之美

    小红书是深受年轻人喜爱的生活社交类社区平台,越来越多的人在小红书上分享旅行.日常.心情.近日,不少使用鸿蒙原生版小红书的细心用户已经发现,直接使用小红书拍摄照片与自己使用原相机拍摄有一样清晰美观的呈现 ...

  2. Hanoi-C

    什么是汉诺塔?汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命 ...

  3. 『Plotly实战指南』--折线图绘制基础篇

    在数据分析的世界中,折线图是一种不可或缺的可视化工具. 它能够清晰地展示数据随时间或其他变量的变化趋势,帮助我们快速发现数据中的模式.趋势和异常. 无论是金融市场分析.气象数据监测,还是业务增长趋势预 ...

  4. npm 如何更新项目最新依赖包

    NPM 是什么? Node 软件包管理器(NPM)提供了各种功能来帮助你安装和维护项目的依赖关系. 由于错误修复.新功能和其他更新,依赖关系可能会随着时间的推移而变得过时.你的项目依赖越多,就越难跟上 ...

  5. go strings包

    //是否包含指定的字符串中任意一个字符 有一个出现过 就返回true fmt.Println(strings.ContainsAny(s1,"glass")) //返回指定字符出现 ...

  6. mysql grant 用户权限

    用户添加授权 mysql> grant all privileges on *.* to 'niuben'@'%' identified by '123456' with grant optio ...

  7. 神经网络与模式识别课程报告-卷积神经网络(CNN)算法的应用

    ======================================================================================= 完整的神经网络与模式识别 ...

  8. AI穿上身:苹果手表如何改变你的生活?

    楔子:一个普通理工男的科技启示录 我是张三,一个标准的90后理工男.在这个日新月异的科技时代,我习惯用精密的逻辑和近乎机械的效率来审视世界.每天早上6点45分准时起床,每一分钟都被精确地规划,生活就像 ...

  9. Java的IO模型、Netty原理详解

    1.什么是IO 虽然作为Java开发程序员,很多都听过IO.NIO这些,但是很多人都没深入去了解这些内容. Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的 ...

  10. linux中安装firebird

    本在树莓派上安装sqlite,因为sqlite的多用户需要自己控制读写.最终选择稳定够用的fb2.5. 嵌入式无论哪一种fb都差不多. 1.安装 sudo apt-get install firebi ...