1 条题解
-
0
自动搬运
来自洛谷,原作者为

热言热语
try { hard } catch (dream) {} finally { AFO } —— PinkRabbit 是信仰搬运于
2025-08-24 21:23:53,当前版本为作者最后更新于2017-07-26 16:55:13,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
主要的算法是欧拉路。
题目要求每条木棍都用过,同颜色的两端可以相接,
如果没有字符串处理,几乎是一道欧拉路的模板题把每种颜色看做一个点,木棍看做连接两种颜色的无向边,整个问题就转化成了求这个图是否存在欧拉路。
对于点的编号,可以采用字典树或者用STL里的unordered_map(map会超时)。重要:建议不选STL,非常慢……
接下来就是欧拉路的判定。
首先图必须是联通的。楼下给出了用dfs的方法,这里给出用并查集的方法。
对于所有的点建立一个并查集。对于每条边,尝试把它两端的点合并,并记录有效合并(即合并前两个点不在同一组中)的次数。
设点(注意不是边)的数量为N,有效合并次数为M,则当且仅当M==N-1时图是联通的。下面给出简单说明:
如果图是联通图,并查集就只有一个组。而初始有N个组,每次有效合并会减少一个组,最后只剩一个组,所以有效合并次数M=N-1。
其次(也是最后),图中奇数度数的点的个数必须为0(最后回到出发点)或2(一个点出发,另一个点结束)。对此,输入时记录每个点度数,最后全部扫一遍即可。
代码
核心部分代码如下:
#include <stdio.h> #define N 500010//题目中说最多有250000条边,也就是最多有500000个点 int n=0,deg[N];char s[15];//n:点数(颜色数),deg:每个点度数 /*求编号部分(getid)*/ //... /*并查集*/ int fa[N]; inline int find(int a) { return fa[a]?fa[a]=find(fa[a]):a; } inline bool join(int a,int b) {//有效合并返回true,无效返回false int x=find(a),y=find(b); if(x==y) return false; fa[x]=y;return true; } /********************/ inline bool check() { int x,y,cnt=0; while(~scanf("%s",s)) { x=getid(s); scanf("%s",s); y=getid(s);//getid求编号 if(join(x,y)) ++cnt;//记录有效合并次数 ++deg[x];++deg[y];//统计度数 } if(cnt<n-1) return false;//判联通:只有当cnt==n-1时是联通的 cnt=0;//记录奇数度点的个数 for(int i=1;i<=n;++i) if((deg[i]&1)&&++cnt>2) return false;//扫一遍颜色的度,奇数度点个数>2就退出 return true; } int main() { puts(check()?"Possible":"Impossible"); return 0; }求编号的部分(两种做法):
/*1.Trie/字典树*/ int nd=1,root=1;struct node{int son[26],num;}t[1000010]; int getid(const char *s) { int k=root;char c; for(int i=0;s[i];++i) { c=s[i]-'a'; if(!t[k].son[c]) t[k].son[c]=++nd;//动态开点 k=t[k].son[c]; } if(!t[k].num) t[k].num=++n; return t[k].num; } /*2.unordered_map*/ #include <string> #include <unordered_map> using namespace std; unordered_map<string,int> M; int getid(const char *s) { return M[s]?M[s]:M[s]=++n; }
- 1
信息
- ID
- 331
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者