poj1386:http://poj.org/problem?id=1386
题意:给你n个单词,问你是否能够通过调整单词的顺序存在这样的一个序列,使得 每个单词的首字母是前一个单词的尾字母。
题解:每个单词可以看做从首字母连向尾字母的一条边,然后就是整个图的欧拉路径。统计每个点的入度和初度,如果基图连通,并且只有两个点入度和初度不等,并且相差分别为1,-1,就存在这样的路径,否则则没。 连通性,可以用并查集. 处理完之后,看每个点的父亲是否相等来判断是否连通。
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 using namespace std; 6 int in[27], pa[27], out[27];// 统计入度,初读 7 bool used[27];//记录出现过的字母 8 int n;//单词的个数 9 char str[1000];//读取单词 10 void UFset(){//初始化 11 for(int i=1;i<=26;i++){ 12 used[i]=0; 13 pa[i]=-1; 14 out[i]=0; 15 in[i]=0; 16 } 17 } 18 int Find(int x){//查找 19 int s; 20 for(s=x;pa[s]>=0;s=pa[s]); 21 while(s!=x){ 22 int temp=pa[x]; 23 pa[x]=s; 24 x=temp; 25 } 26 return s; 27 } 28 void Union(int R1,int R2){//合并 29 int r1=Find(R1); 30 int r2=Find(R2); 31 int temp=pa[r1]+pa[r2]; 32 if(pa[r1]>pa[r2]){ 33 pa[r1]=r2; 34 pa[r2]=temp; 35 } 36 else{ 37 pa[r2]=r1; 38 pa[r1]=temp; 39 } 40 } 41 bool solve(){//判断连通性 42 int first=-1; 43 for(int i=1;i<=26;i++){ 44 if(!used[i])continue; 45 if(first==-1)first=Find(i); 46 else if(first!=Find(i))return false; 47 } 48 return true; 49 } 50 int main(){ 51 int cas; 52 scanf("%d",&cas); 53 while(cas--){ 54 scanf("%d",&n); 55 UFset(); 56 for(int i=1;i<=n;i++){//建图 57 scanf("%s",str); 58 int len=strlen(str); 59 int u=str[0]-'a'+1; 60 int v=str[len-1]-'a'+1; 61 in[v]++; 62 used[v]=true; 63 out[u]++;used[u]=true; 64 if(Find(u)!=Find(v)) 65 Union(u,v); 66 } 67 int one=0,one1=0;bool flag=true; 68 for(int j=1;j<=26;j++){ 69 if(!used[j])continue; 70 if(out[j]-in[j]>=2||in[j]-out[j]>=2){ 71 flag=false; 72 break; 73 } 74 if(out[j]-in[j]==1){ 75 one++; 76 if(one>1) 77 {flag=false;break;} 78 } 79 if(out[j]-in[j]==-1){ 80 one1++; 81 if(one1>1){ 82 flag=false;break; 83 } 84 } 85 } 86 if(one!=one1)flag=false; 87 if(!solve())flag=false; 88 if(flag)printf("Ordering is possible. "); 89 else 90 printf("The door cannot be opened. "); 91 } 92 }