题意大概是,让你每次输入两个颜色单词,表示这是连成一条木棍的单词(从这可以看出这是一个无向图,因为无前后关系),然后他要求说能否根据这个拼接成一条路线,把所有的木棍都应连接,把木棍看成边,单词看成点,就是要让你把所有的边都连一遍,当然是不重复也不漏的,这恰好是无向图欧拉通路的问题。因此要保证图是连通的,而且奇数点的个数要么是0要么是2.
这里判断图的连通用并查集(压缩路径),即看看最后是不是在同一个集合里面,而每个点的度的问题比较简单,难点在于如何表示这个点的状态,这里我们用字典树,然后用全局变量color记录当前已经出现的颜色的个数,返回这个数字表示这个状态(单词)。
这里用字典树的好处在哪?这里相当于用内存换时间的方法。所以搜索只要O(1)时间。假如不用字典树的话,那你每次都要遍历所有的单词。
#include<cstdio> #include<iostream> #include<string.h> using namespace std; #define MAXN 500010 struct trieTreeNode{ int id; struct trieTreeNode* next[27]; bool flag; trieTreeNode() { flag=false; id=0; memset(next,0,sizeof(next)); } }root; int color=0; int p[MAXN],degree[MAXN]; int find(int x) { if(p[x]!=x) p[x]=find(p[x]); return p[x]; } void Union(int a,int b) { int x1=find(a); int x2=find(b); if(x1!=x2) p[x1]=x2; return ; } int hash(char *str) { struct trieTreeNode* ptr=&root; int len=0; while(str[len]!='\0'){ int index=str[len++]-'a'; if(!ptr->next[index]){ ptr->next[index]= new trieTreeNode; } ptr=ptr->next[index]; } if(ptr->flag==1){ return ptr->id; } else{ ptr->flag=true; ptr->id=color++; return ptr->id; } } int main() { //initial for(int i=0;i<MAXN;i++) { p[i]=i; degree[i]=0; } char str1[11],str2[11]; int count=0; while(cin>>str1>>str2){ int a,b; a=hash(str1); b=hash(str2); degree[a]++;degree[b]++; Union(a,b); } int s=find(0),num=0,yes=1;//num统计奇数节点的个数 for(int i=0;i<color;i++) { if(degree[i]%2==1)num++; if(find(i)!=s)yes=0; } if(num!=0 && num!=2)yes=0; if(yes)cout<<"Possible"<<endl; else cout<<"Impossible"<<endl; return 0; }