这一题是典型的欧拉道路题目。 欧拉道路的定义是: 除了起点和终点外, 其他点的“进出” 次数应该相等。 换句话说,除了起点和终点外, 其他点的度数应该是偶数。
对于有向图, 则必须其中一个点的出度恰好比入度大1, 另一个的入度比出度大。
如果奇点数不存在的话, 则可以从任意点出发,最终一定会回到该点(成为欧拉回路)。
题目给的单词量比较大,但是有用的只有首和尾的字母,所以只需要存首尾字母就可以了。
欧拉道路还有关键的一步是判断这一个图是连通的, 并且只有一个一个连通分支。
1️⃣、用DFS判断连通
2️⃣、入度和出度最多只有两个不相等,且一个入度比出度大一,一个出度比入度大一。
#include<bits/stdc++.h>
using namespace std;
#define maxn 2000
int n, m, G[maxn][maxn];
int a, b, in[maxn],out[maxn];
bool vis[maxn];
void init()
{
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(G,0,sizeof(G));
memset(out,0,sizeof(out));
}
void dfs(int x)
{
for(int i = 0; i <27; ++i)
{
if(G[x][i] && !vis[i]) vis[i] = 1, dfs(i);
}
}
void judge()
{
bool flag=true;
int n1=0,n2=0;
for(int i = 0; i <27; ++i)
{
if(!flag)
break;
if(in[i]!=out[i])
{
if(in[i]==out[i]+1)
n1++;
else if(in[i]+1==out[i])
n2++;
else
flag=false;
}
}
if(n1&&n2&&n1+n2>2)
flag=false;
if(flag)
{
int cnt = 0;
for(int i = 0; i <27; ++i)
{
if(out[i])
{
vis[i] = 1, dfs(i);
break;
}
}
bool flag2=true;
for(int i=0;i<27;i++)
{
if(in[i]&&!vis[i])flag2=false;
if(out[i]&&!vis[i])flag2=false;
}
if(flag2)
cout<<"Ordering is possible."<<endl;
else
cout<<"The door cannot be opened."<<endl;
}
else
cout<<"The door cannot be opened."<<endl;
}
int main()
{
int T;
cin>>T;
while(T--)
{
init();
char a[1005];
cin>>n;
for(int i=0; i<n; i++)
{
cin>>a;
int l=strlen(a)-1;
G[a[0]-'a'][a[l]-'a']++;//此处及以下out和in的下标顺序一定要一致,不然WA
out[a[0]-'a']++;
in[a[l]-'a']++;
}
judge();
}
return 0;
}