由于题目的单词个数太大,不可能也没必要记录每个单词。
所以只要记录首尾两个单词即可。
又由于只有26个点(a~z),而且是判断有向的欧拉回路\欧拉通路
so,用in,out数组分别记录每个点的出入度,然后结尾比较所有出现的点的出入度是否相等,或者有除首位两个点(出度入度之差分别为1和-1)外其他点都相等即可。
由于懒得将小写字母的ASCII码转化为0~25,于是直接开了300的数组(其实130就够了)(‘a' = 97)
还有一个问题就是要处理所有点是否在同一个连通图上(用并查集即可)(例如数据 ava,cvc是不满足题意的,不过却满足有向图欧拉回路\通路的判定条件)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
const int maxx = 200;
int in[maxx];
int out[maxx];
int father[maxx];
bool vis[maxx];
int Find(int x)
{
while(x!=father[x])
x = father[x];
return x;
}
void Union(int r1,int r2)
{
int a = Find(r1);
int b = Find(r2);
if(a!=b)
father[a] = b;
}
bool check(int a, int b)
{
int r1 = in[a] - out[a];
int r2 = in[b] - out[b];
if((r1==1 && r2==-1) || (r1==-1 && r2==1)) return true;
else return false;
}
int main()
{
// freopen("1386.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i='a'; i<='z'; i++)
father[i] = i;
int n;
scanf("%d",&n);
int x;
while(n--)
{
string tem;
cin>>tem;
int a = tem[0];
int b = tem[tem.length()-1];
in[b]++;
out[a]++;
vis[a] = true;
vis[b] = true;
Union(a,b);
x = a;
}
int different = 0;
int line = 0;
int odd_a = 0;
int odd_b = 0;
x = Find(x);
for(int i='a'; i<='z'; i++)
{
if(vis[i])
{
if(out[i] != in[i])
{
different++;
if(!odd_a) odd_a = i;
else if(!odd_b) odd_b = i;
else//如果有三个数以上出入度不同,直接跳出
{
line = 1;
break;
}
}
if(Find(i)!=x)
{//如果出现过的点的父亲节点不同,跳出
line = 1;
break;
}
}
}
if(line==0 && different==0) printf("Ordering is possible.\n");
else if(line==0 && different == 2 && check(odd_a,odd_b)) printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}