题目链接:http://poj.org/problem?id=2513
题目大意: 给出无数根筷子,每个筷子头尾各一个单词代表颜色
颜色相同则可以拼在一起
如 blue red 的筷子和 red violet 的筷子可以拼在一起
如 red blue 的筷子和 red violet 的筷子也可以拼在一起
筷子不分头尾,可以任意调换
问所有的筷子能否拼成一条线?
解题思路: 把每个单词看成一个点,每根筷子就代表一条边!
这样就能得到一个图
所有筷子连成一条线,换句话说就是一次遍历所有的边
然后可以转化成"一笔连成"的问题,无向图的欧拉通路!
奇数度顶点的数量0或2时,欧拉通路成立
先判断这个图是不是连通图(并集合)
边数太多,输入的时候如果用strcmp判断是哪个点会TLE
我们可以用Hash来处理
代码:
//BKDRHash + 欧拉回路 + 并查集 #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 251000 int parent[MAX]={0},v[MAX]={0}; unsigned int BKDRHash(char *str) { unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF)%MAX; } void Empty() //初始化parent[] { int i; for(i=0;i<MAX;i++) parent[i]=i; } int Find(int x) //并查集 Find() { int s,j; s=x; while(x!=parent[x]) { x=parent[x]; } while(s!=x) { j=parent[s]; parent[s]=x; s=j; } return x; } void Union(int r1,int r2) //并查集 Union() { int R1,R2; R1=Find(r1); R2=Find(r2); if(R1!=R2) { parent[R1]=R2; } } int main() { char a[11],b[11]; int i,pd,js,atemp,btemp,tempx; Empty(); //别忘记初始化了! while(scanf("%s%s",a,b)!=EOF) { atemp=BKDRHash(a); //返回 哈希值 btemp=BKDRHash(b); //返回 哈希值 v[atemp]++; //顶点的度++ v[btemp]++; //顶点的度++ if(Find(atemp)!=Find(btemp)) { Union(atemp,btemp); } } for(i=0,js=0;i<MAX;i++) { if(v[i]>0&&v[i]%2!=0) js++; //顶点的度为奇数的数目 } if(js!=0&&js!=2) { printf("Impossible\n"); return 0; } for(i=0,tempx=-1,pd=1;i<MAX;i++) { if(v[i]>0) { if(tempx==-1) { tempx=Find(i); //**寻找祖先,是Find() } else if(tempx!=Find(i)) //**祖先不同 就不符合,不是连通图 { pd=0; printf("Impossible\n"); return 0; } } } printf("Possible\n"); return 0; }注:原创文章,转载请注明出处