POJ 1386 Play on Words(判定图欧拉通路是否存在)(并查集+有向图存在欧拉路)

参考博客

题目来源

大意:给你多个单词,问你能不能将所有单词组成这样一个序列:序列的前一个单词的尾字母与后一个单词的头字母相同.
思路分析:

 把每个单词看成一条有向边,把26个字母看成是图的节点.这就是一个问你有向图是否存在欧拉通路/回路的问题.
        有向图存在欧拉路必须满足两个条件:
        1.    有向图弱连通
        2.    图中所有点入度==出度 或只有两个点的入度!=出度且这两个中一个入度-出度=1,另一个出度-入度=1.
注意:这里每个单词必须看成有向边,而不能看成无向边.因为对于每个单词来说只能从单词头走到单词尾.

代码:

#include<cstdio>  
#include<cstring>  
using namespace std;  
const int maxn=26+5;  
int fa[maxn];  
int in[maxn],out[maxn];  
int m;//单词数  
int findset(int u)  
{  
    if(fa[u]==-1) return u;  
    return fa[u]=findset(fa[u]);  
}  
int main()  
{  
    int T; 
    scanf("%d",&T);  
    while(T--)  
    {  
        memset(in,0,sizeof(in));  
        memset(out,0,sizeof(out));  
        memset(fa,-1,sizeof(fa));  
        scanf("%d",&m);  
        for(int i=0;i<m;i++)  
        {  
            char str[1200];  
            scanf("%s",str);  
            int len=strlen(str);  
            int u=str[0]-'a', v=str[len-1]-'a';  
            in[u]++;  
            out[v]++;  
            u=findset(u), v=findset(v);  
            if(u!=v) 
                fa[u]=v;  
        }  
        int cnt=0;  
        for(int i=0;i<26;i++)  
            if( (in[i]||out[i]) && findset(i)==i ) //&&&
                cnt++;  
        if(cnt>1)  
        {  
            printf("The door cannot be opened.\n");  
            continue;  
        }  
        int c1=0, c2=0, c3=0;//分别表示入度!=出度时的三种情况  
        for(int i=0;i<26;i++)  
        {  
            if(in[i]==out[i]) continue;  
            else if(in[i]-out[i]==1) c1++;  
            else if(out[i]-in[i]==1) c2++;  
            else c3++;  
        }  
        if( ( (c1==c2&&c1==1)||(c1==c2&&c1==0) )&&c3==0 )  //这个地方不能忘记第二种全为0的情况,否则WA
            printf("Ordering is possible.\n");  
        else  
            printf("The door cannot be opened.\n");  
    }  
    return 0;  
}  



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值