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

思路:

分别存下每个字符串的首尾字符,以字符为结点,单词看作一条变,就变成了求欧拉回路了,先判断下图是否连通,然后根据欧拉回路的结论:最多只能有两个点的入读不等于初读,而且必须是一个点的出度恰好比入度大1(将它作为起点),另一个的入度比出度大1(将它作为终点);

实现代码:

#include<iostream>
#include<cstring>
using namespace std;
const int M = 30;
int f[M];
int in[M],out[M];
int fd(int x) {return f[x]==x? x:f[x]=fd(f[x]);}
void mix(int a,int b) {a=fd(a);b=fd(b);if(a!=b) f[a]=b;}
void init(){
    for(int i = 0;i <= M;i ++){
        f[i] = i;
    }
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}

int main()
{
    string s;
    int t,n;
    cin>>t;
    while(t--){
        init();
        cin>>n;
        for(int i = 0;i < n;i ++){
            cin>>s;
            int len = s.size();
            int x = s[0] - 'a';
            int y = s[len-1] - 'a';
            in[x]++; out[y]++;
            //cout<<x<<" "<<y<<endl;
            mix(x,y);
        }
        int ans = 0;
        for(int i = 0;i < 26;i ++){
            if(i==f[i]&&(in[i]||out[i])){
                ans++;
            }
        }
        //cout<<ans<<endl;
        bool flag = true;
        int num1 = 0,num2 = 0;
        if(ans == 1){
            for(int i=0;i<=26;i++){
            if(in[i]!=out[i]){
                if(in[i]+1==out[i]) num1++;
                else if(in[i]==out[i]+1) num2++;
                else{
                    flag = false;break;
                }
            }
            }
            if(num1&&num2&&num1+num2>2) flag = false;
        }
        else flag = false;
        if(flag) cout<<"Ordering is possible."<<endl;
        else cout<<"The door cannot be opened."<<endl;
    }
    return 0;
}

 

posted @ 2018-03-08 21:17  冥想选手  阅读(147)  评论(0编辑  收藏  举报