这题,可以转换成有向图的欧拉回路的判断。
有向图的判断方法:所以点的入度等于出度或者有一个点的出度比入度大1有一个点的入度比出度大1,剩下的点入度等于出度。
不过还有一个前提,就是图是连通的,可以用DFS来判断或者并查集。我用的是并查集。
代码:
#include <iostream>
#include <cstring>
using namespace std;
struct node
{
int indegree, outdegree;
};
int pre[30], flag[30];
node degree[30];
bool ans;
int finds(int x) //并查集查找函数
{
int r = x;
while(pre[r] != r)
r = pre[r];
int i = x, j;
while(i != r)
{
j = pre[i];
pre[i] = r;
i = j;
}
return r;
}
void join(int x, int y) //并查集合并函数
{
int fx = finds(x);
int fy = finds(y);
if(fx != fy)
pre[fx] = fy;
}
int main()
{
// freopen("1.txt", "r", stdin);
int t, n, len, i;
char str[1005];
cin >> t;
while(t--)
{
cin >> n;
ans = false;
for(i = 0; i < 30; i++)
{
pre[i] = i;
degree[i].indegree = degree[i].outdegree = 0;
}
memset(flag, 0, sizeof(flag));
while(n--)
{
cin >> str;
len = strlen(str);
flag[str[0] - 'a'] = flag[str[len - 1] - 'a'] = 1;
join(str[0] - 'a', str[len - 1] - 'a');
degree[str[0] - 'a'].outdegree++;
degree[str[len - 1] - 'a'].indegree++;
}
i = 0; //判断图是否连通
while(flag[i] == 0) i++;
int par = finds(i);
for( ; i < 26; i++)
if(flag[i] && finds(i) != par)
{
ans = true;
break;
}
if(ans)
cout << "The door cannot be opened." << endl;
else //判断是否存在欧拉回路
{
int a, b, c, count;
a = b = c = count = 0;
for(i = 0; i < 26; i++)
{
if(flag[i])
{
count++;
if(degree[i].indegree - degree[i].outdegree == 1)
a++;
else if(degree[i].indegree - degree[i].outdegree == -1)
b++;
else if(degree[i].outdegree == degree[i].indegree)
c++;
}
}
if((a == 1 && a == b && c == count - 2) || (a == 0 && a == b && c == count))
cout << "Ordering is possible." << endl;
else
cout << "The door cannot be opened." << endl;
}
}
return 0;
}