题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1116
题意:给我们一些单词,问我们可不可以找到字母收尾相接的顺序得到口令打开门,通俗一点就是一个单词的结尾和下一个单词的开头相接可不可以把所有的单词给遍历完。
其实这题就是相当于一个欧拉回路的判断,因为一个单词的收尾关系是定的,实际上给的我们是一个有向图,首先我们得确定这个图是否联通,判断的方法可以借助并查集,在判断完联通后便统计每个出现过的字母的入度和出度,对于一个有向图,满足条件的可能有两种,成环的话所有点的出度 == 入度,成链的话在首端的入度+1 == 出度,在尾端入度 == 出度+1。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn = 30;
int set[maxn],in[maxn],out[maxn];
char str[1005];
bool vis[maxn];
int find(int x)
{
int r = x;
while(set[r] != r)
r = set[r];
return r;
}
void merge(int x,int y)
{
int a,b;
a = find(x);
b = find(y);
if(a != b)
set[a] = set[b];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(vis,0,sizeof(vis));
for(int i=0; i<26; i++) set[i] = i;
int n;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%s",str);
int s = str[0]-'a';
int e = str[strlen(str)-1]-'a';
merge(s,e);
out[s]++;
in[e]++;
vis[s] = vis[e] = 1;
}
int root = 0, innum = 0, outnum = 0,flag = 0;
for(int i=0; i<26; i++)
if(vis[i])
{
if(set[i] == i)
root++;
if(in[i] != out[i])
{
if(in[i] == out[i]+1)
innum++;
else if(out[i] == in[i]+1)
outnum++;
else flag = 1;
}
if(root > 1)
{
flag = 1;
break;
}
}
if(flag)
printf("The door cannot be opened.\n");
else if((innum == 1 && outnum == 1) || (innum == 0 && outnum == 0))
printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}