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

2.解题思路:本题利用欧拉回路存在条件解决。可以将所有的单词看做边,26个字母看做端点,那么本题其实就是问是否存在一条路径,可以到达所有出现过的字符端点。由于本题还要求了两个单词拼在一起的条件是前一个单词的右端点和本单词的左端点一样。所以这是一个有向图。根据结论:有向图的底图(忽略边的方向后的图)必须连通;有向图中最多只能有两个端点的入度不等于出度,且必须是其中一点的入度比出度小1,另一点的入度比出度大1。因此先判断端点是否都连通,再判断每个端点的度数是否满足结论即可。

那么,如何判断连通性呢?第一种方法是利用DFS,第二种方法可以利用并查集。本题利用并查集来判断是否连通。

 

  1 #pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<math.h>
  7 #include<algorithm>
  8 #include<queue>
  9 #include<set>
 10 #include<bitset>
 11 #include<map>
 12 #include<vector>
 13 #include<stdlib.h>
 14 #include <stack>
 15 using namespace std;
 16 int dirx[]={0,0,-1,1};
 17 int diry[]={-1,1,0,0};
 18 #define PI acos(-1.0)
 19 #define max(a,b) (a) > (b) ? (a) : (b)
 20 #define min(a,b) (a) < (b) ? (a) : (b)
 21 #define ll long long
 22 #define eps 1e-10
 23 #define MOD 1000000007
 24 #define N 100006
 25 #define inf 1e12
 26 int n;
 27 int u[N],v[N];
 28 int in[N],out[N];
 29 int vis[N];
 30 int fa[N];
 31 int num;
 32 void init(){
 33    memset(in,0,sizeof(in));
 34    memset(out,0,sizeof(out));
 35    memset(vis,0,sizeof(vis));
 36    for(int i=0;i<N;i++){
 37        fa[i]=i;
 38    }
 39    num=0;
 40 }
 41 /
 42 int find(int x){
 43    return fa[x]==x?x:fa[x]=find(fa[x]);
 44 }
 45 void merge(int x,int y){
 46    int root1=find(x);
 47    int root2=find(y);
 48    if(root1==root2) return;
 49    fa[root1]=root2;
 50 }
 51 //
 52 void solve(){
 53 
 54     for(int i=0;i<n;i++){
 55         merge(u[i],v[i]);
 56     }
 57     int i=0;
 58     for(i;!vis[i];i++);
 59 
 60     int x=find(i);//判断能否连通
 61     for(int j=i+1;j<26;j++){
 62         if(vis[j]){
 63            int y=find(j);
 64            if(x!=y){
 65                printf("The door cannot be opened.\n");
 66                return;
 67            }
 68         }
 69     }
 70 
 71     int flag=1;
 72     int cnt=0;
 73     for(int i=0;i<26;i++){
 74         if(vis[i]){
 75            if(in[i]!=out[i]){
 76               if(in[i]==out[i]-1) cnt++;
 77               else if(in[i]==out[i]+1) cnt++;
 78               else{
 79                   flag=0;
 80                   break;
 81               }
 82            }
 83            if(cnt>2){
 84                flag=0;
 85                break;
 86            }
 87         }
 88     }
 89     if(flag){
 90         printf("Ordering is possible.\n");
 91     }
 92     else{
 93         printf("The door cannot be opened.\n");
 94     }
 95 
 96 }
 97 int main()
 98 {
 99    int t;
100    scanf("%d",&t);
101    while(t--){
102 
103          init();
104 
105          char s[1006];
106          scanf("%d",&n);
107          for(int i=0;i<n;i++){
108              scanf("%s",s);
109              int len=strlen(s);
110              int a=s[0]-'a';
111              int b=s[len-1]-'a';
112              u[i]=a,v[i]=b;
113              in[a]++,out[b]++;
114              vis[a]=1;
115              vis[b]=1;
116          }
117          solve();
118    }
119     return 0;
120 }
View Code

 

转载于:https://www.cnblogs.com/UniqueColor/p/4839773.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值