题意:给出n个单词,问是否可以把所有单词都拍成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同(想象成语接龙)
分析:不难发现,除了起始单词和结束单词,每个单词均连接了两个单词(一进一出),而起始单词只有出,结束单词只有进,
把每个单词抽象为一个点,会发现这是有像图的欧拉路问题,当存在欧拉路时,存在解,有向图存在欧拉路的条件是,忽略边的方向原图连通,除起点和终点外,所有点的出入度都相等,起点 出度=入度+1,终点 出度+1=入度
代码中用并查集判断图的连通性,可以dfs写
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e5+200;
int in[30],ou[30],f[N],vis[N];
vector<int>e[30];
string s[N];
int getf(int x)
{
return f[x]==x?x:f[x]=getf(f[x]);
}
void mix(int x,int y)
{
int tx=getf(x),ty=getf(y);
if(tx!=ty)
f[tx]=ty;
}
int main()
{
ios::sync_with_stdio(0);
int t,n;
cin>>t;
while(t--)
{
mem(in,0);
mem(ou,0);
mem(vis,0);
for(int i=0;i<26;i++)
e[i].clear();
cin>>n;
for(int i=1; i<=n; i++)
{
f[i]=i;
cin>>s[i];
e[s[i][0]-'a'].push_back(i);
int l=0,r=s[i].length()-1;
in[s[i][l]-'a']++;
ou[s[i][r]-'a']++;
}
for(int i=1;i<=n;i++)
{
int r=s[i][s[i].length()-1]-'a';
for(int j=0;j<e[r].size();j++)
mix(i,e[r][j]);
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(!vis[getf(i)])
{
vis[getf(i)]=1;
ans++;
}
}
int f1=0,f2=0;
for(int i=0;i<26;i++)
{
if(in[i]!=ou[i])
{
if(in[i]==ou[i]+1&&!f2)
f2=1;
else if(in[i]+1==ou[i]&&!f1)
f1=1;
else
{
f2=f1=-1;
break;
}
}
}
if(ans!=1)cout<<"The door cannot be opened."<<endl;//图不连通
else
{
if(f1==1&&f2==1||f1==0&&f2==0)
cout<<"Ordering is possible."<<endl;
else
cout<<"The door cannot be opened."<<endl;
}
}
return 0;
}