UVA - 10129 - Play on Words (欧拉路+并查集)

58 阅读1分钟

题意:

对于给出的单词,判断能否首尾相连,变成一串。有点串珠子的感觉。

思路:

只要判断是否为欧拉路就可以得出结果。欧拉路形成的前提是所给的图是连通的,这就要用到并查集进行判断。在连通的前提下,形成欧拉路可以有两种状态:

1.所有点的出度都等于入度。

2.除了起点出度比入度大一,终点出度比入度小一,其他点出度都等于入度。

二者满足一种即可。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char te[1100];
int pre[28];
int vis[28],du[28];
int T,n,x,y,len,t,flag;
void de(){
	for(int i=0;i<28;i++)
		pre[i]=i;
}
int find(int x)  
{  
    if (x != pre[x])  
    {  
        pre[x] = find(pre[x]); 
    }  
    return pre[x];  
}  // return pre[x] == x?x:pre[x] = find(pre[x]); //可以用这句代替 
int main(){
	
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		de();
		memset(vis,0,sizeof(vis));
		memset(du,0,sizeof(du));
	
		flag=1;
		for(int i=0;i<n;i++){
			scanf("%s",te);
			len=strlen(te);
			x=te[0]-'a';y=te[len-1]-'a';
			vis[y]=vis[x]=1;
			du[x]++;du[y]--;
			x=find(x);	
			pre[y]=x;
				
		}
		for(int i=0;i<26;i++)//再次压缩路径
			find(i);
		for(int i=0;i<26;i++)
			if(vis[i]==1) {
			t=pre[i]; break;
			}
		for(int i=0;i<26;i++){
			if(vis[i]==1&&t!=pre[i]) {
			     flag=0;break;
			}	
			
		}
		if(flag==0) {cout<<"The door cannot be opened."<<endl;
			 
		} 
		else{
				int fr=0,be=0,i=0;
					for(;i<26;i++){
						if(du[i]==1) fr++;
						else if(du[i]==-1) be++;
						else if(du[i]!=0){
						break;
						}
					}
				if(i!=26) cout<<"The door cannot be opened."<<endl;
				else if((fr==1&&be==1)||(fr==0&&be==0)) cout<<"Ordering is possible."<<endl; 
				else cout<<"The door cannot be opened."<<endl;
		}
		
		
	}

return 0;} 


\