题意:
给你一连串的单词,每个单词只要能够首位相连就可以输出 Ordering is possible.否则输出The door cannot be opened.
解题思路:
典型的欧拉回路,把每个单词的首字母跟尾字母作为节点,然后算每个节点的入度跟出度,
1.首先应判断这个图是否有连通分量,如果有连通分量,那么这个图就不满足。
2.当图没有连通分量满足时,算如果每个节点的入度于出度都是偶数,那么就是一个欧拉回路,这种情况满足。
另一种是欧拉通路,即一个节点只有入度,另一个节点只有出度就可以满足。
发发牢骚:
因为初始化的时候i=1;i<=MAX;i++时这个=号越界了,搞得我头都大了。。
玄得狠,不过也证明一个问题,熟悉的错不了,认真分析一遍还是可以分析出来的,细心透彻地分析很重要。
代码:
#include<iostream> #include<string> using namespace std; const int MAX=30; int father[MAX],dep[MAX],in[MAX],out[MAX],visited[MAX]; int find_set(int x) { if(x!=father[x]) { father[x]=find_set(father[x]);//回溯压缩路径 } /*所有的子节点的根都归到boss下*/ return father[x]; } void union_set(int f1,int f2) { f1=find_set(f1); f2=find_set(f2); if(f1==f2) return ; if(dep[f1]>dep[f2]) { father[f2]=f1; } else { if(dep[f1]==dep[f2]) { dep[f2]++; } father[f1]=f2; } return ; } void init() { for(int i=0;i<MAX;i++) { father[i]=i;//父节点 dep[i]=0;//并查集的秩 in[i]=0; out[i]=0; visited[i]=0;//节点是否访问过 } } int main(void) { int cas,num,i,a,b,flag,count,k,p[MAX]; string str; scanf("%d",&cas); while(cas--) { scanf("%d",&num);//单词个数 init(); for(i=1;i<=num;i++) { cin>>str; a=str[0]-'a'; b=str[str.size()-1]-'a'; in[a]++;//入度 out[b]++;//出度 visited[a]=1; visited[b]=1; union_set(a,b); } /*判断有向图是否连通*/ for(i=0,count=0;i<MAX;i++) { if((visited[i])&&father[i]==i) count++; } flag=0;//通 if(count!=1) { cout<<"The door cannot be opened."<<endl; continue; } for(i=0,k=0;i<MAX;i++) { if(in[i]!=out[i])//找出入度与出度不相同的点 p[k++]=i; } if(k==0||k==2)//白开水思路 { if(k==0) { flag=0; } else { if( out[p[0]]-in[p[0]]==1 && in[p[1]]-out[p[1]]==1 ||( out[p[1]]-in[p[1]]==1 && in[p[0]]-out[p[0]]==1 ) ) { flag=0; } else flag=1; } } else { flag=1; } if(flag) cout<<"The door cannot be opened."<<endl; else cout<< } //system("pause"); return 0; } |