poj1386--Play on Words--欧拉路

Description

给你若干个单词,一个单词能拼接到前一个单词的标准是:此单词的首字母和前一个单词的尾字母相同。

Sample Input

3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok

Sample Output

The door cannot be opened.
Ordering is possible.
The door cannot be opened.

题解:

  构图:每个单词对应一条有向边,从此单词的首字母连向尾字母。如果其中存在欧拉路,说明可以拼接成链(欧拉通路)或环(欧拉回路)。

  首先存储字母出现的信息,因为是多组数据,注意每次要初始化记录数组。

  同时用used数组标记该字母是否出现在图中,in数组和out数组分别记录入度和出度。

  用一个并查集对整个构成的图做合并处理,判断此图是否没有孤立的点,如果有,说明不连通,需要输出“The door cannot be opend."

  如果整张图联通,进一步遍历这张图。

  接下来判断是否是欧拉路:

  1.如果有任何一个点的出入度之差大于1,就不是欧拉路;

  2.记录出入度不相等的点,如果入度-出度=1的点超过1个,说明终点超过1个,不是欧拉路;

  3.记录出入度不相等的点,如果出度-入度=1的点超过1个,说明起点超过了1个,也不是欧拉路。

  1 #include<algorithm>
  2 #include<cmath>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<iostream>
  6 using namespace std;
  7 const int maxn=100009;
  8 
  9 int n,m,in[maxn],out[maxn],fa[maxn];
 10 bool used[maxn];
 11 
 12 void init()
 13 {
 14     memset(used,0,sizeof(used));
 15     memset(in,0,sizeof(in));
 16     memset(out,0,sizeof(out));
 17     for(int i=1;i<=n;i++)
 18         fa[i]=i;
 19 }
 20 
 21 int find(int x)
 22 {
 23     if(x!=fa[x])
 24         fa[x]=find(fa[x]);
 25     return fa[x];
 26 }
 27 
 28 void uni_set(int x,int y)
 29 {
 30     int u=find(x),v=find(y);
 31     if(u==v)
 32         return;
 33     fa[u]=v;
 34 }
 35 
 36 bool judge_eular()
 37 {
 38     int sta=0,end=0;
 39     for(int i=1;i<=26;i++)
 40     {
 41         if(used[i])
 42         {
 43             if(abs(in[i]-out[i])>1)return 0;
 44             if(in[i]-out[i]==1)
 45             {
 46                 end++;
 47                 if(end>1)return 0;
 48             }
 49             if(out[i]-in[i]==1)
 50             {
 51                 sta++;
 52                 if(sta>1)return 0;
 53             }
 54         }
 55     }
 56     return 1;
 57 }
 58 
 59 int main()
 60 {
 61     int T;
 62     scanf("%d",&T);
 63     while(T--)
 64     {
 65         scanf("%d",&n);
 66         init();
 67         int tmp;
 68         char a[1009];
 69         for(int i=1;i<=n;i++)
 70         {
 71             scanf("%s",a);
 72             int len=strlen(a);
 73             int u=a[0]-'a'+1, v=a[len-1]-'a'+1;
 74             in[v]++;out[u]++;
 75             used[u]=used[v]=1;
 76             tmp=v;
 77             uni_set(u,v);
 78         }
 79         tmp=find(tmp);
 80         bool ok=1;
 81         for(int i=1;i<=26;i++)
 82         {
 83             if(used[i]&&tmp!=find(i))
 84             {
 85                 printf("The door cannot be opened.\n");
 86                 ok=0;
 87                 break;
 88             }
 89         }
 90         if(ok)
 91         {
 92             if(!judge_eular())
 93             {
 94                 printf("The door cannot be opened.\n");
 95                 ok=0;
 96             }
 97             else
 98             {
 99                 printf("Ordering is possible.\n");
100                 ok=1;
101             }
102         }
103     }
104     return 0;
105 }
View Code

转载于:https://www.cnblogs.com/Beckinsale/p/7604806.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值