UVa 10129 单词 (有向欧拉路+并查集)

题目:
输入n个单词,是否可以把这些单词排成一个序列,使得第一个字母和上一个单词的最后一个字母相同。仅包含小写字母例如(acm malform mouse)就可以。
分析:
这是一道判断欧拉路的题目,上篇对欧拉路写了点基本定义。对于这题,把首尾字母看做节点,单词看成是有向边,用并查集判断是否连通,然后再根据有向图的结论:最多只能有两个点的入读不等于出度,而且必须是其中一个点的出度比入度大一,另一个点的入度比出度大一。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1000+5;
int fa[27],in[27],out[27];
int findfa(int x){return x==fa[x]?x:fa[x]=findfa(fa[x]);}
char s[N];
int main()
{
    //freopen("f.txt","r",stdin);
    int T; scanf("%d",&T);
    int n;
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<26;i++)fa[i]=i;
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int len=strlen(s);
            int u=s[0]-'a',v=s[len-1]-'a';
            int x=findfa(u),y=findfa(v);
            fa[x]=y;
            out[u]++; in[v]++;
        }
        int k=0;
        while(in[k]==0&&out[k]==0)k++;
        bool flag=1;
        int x=findfa(k);
        for(int i=k+1;i<26;i++){
            if((in[i]||out[i])&&findfa(i)!=x){flag=false;break;}
        }
        if(!flag){
            printf("The door cannot be opened.\n");continue;
        }
        vector<int>ans;
        for(int i=0;i<26;i++){
            if(in[i]!=out[i])ans.push_back(i);
        }
        if(ans.size()>2){
             printf("The door cannot be opened.\n");continue;
        }
        if(ans.size()==0){
             printf("Ordering is possible.\n");continue;
        }
        if(in[ans[0]]==out[ans[0]]+1&&in[ans[1]]+1==out[ans[1]]
           ||in[ans[1]]==out[ans[1]]+1&&in[ans[0]]+1==out[ans[0]]){
            printf("Ordering is possible.\n");continue;
        }
        printf("The door cannot be opened.\n");
    }
    return 0;
}

你可能感兴趣的:(UVa 10129 单词 (有向欧拉路+并查集))