使用并查集判断连通性,然后再找欧拉通路。
#include <iostream>
using namespace std;
int n;
char st[1005];
bool exist[30];
int in[30], out[30];
int father[30];
int find_father(int a)
{
if (father[a] == a)
return a;
return father[a] = find_father(father[a]);
}
void merge(int a, int b)
{
father[find_father(a)] = find_father(b);
}
void input()
{
scanf("%d", &n);
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(exist, 0, sizeof(exist));
for (int i = 0; i < 26; i++)//初始化并查集
father[i] = i;
for (int i = 0 ; i < n; i++)
{
scanf("%s", st);
in[st[0] - 'a']++;
out[st[strlen(st) - 1] - 'a']++;
merge(st[0] - 'a', st[strlen(st) - 1] - 'a');//构建并查集
exist[st[0] - 'a'] = exist[st[strlen(st) - 1] - 'a'] = true;//把a、b两点记录为访问过的点
}
}
bool ok()
{
int start =0;
int end = 0;
int cnt = 0;
for (int i = 0; i < 26; i++)
if (father[i] == i && exist[i])//如果存在访问过的节点,并且祖先是自己,联通分量加1
cnt++;
if (cnt > 1)//如果不连通
return false;
for (int i = 0; i < 26; i++)
if (in[i] - out[i] == 1)
start++;
else if (out[i] - in[i] == 1)
end++;
else if (out[i] == in[i])
continue;
else
return false;
return start <= 1 && end <= 1;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
input();
if (ok())
printf("Ordering is possible.\n");
else
printf("The door cannot be opened.\n");
}
return 0;
}