题意:每个首尾字母一样的单词可以相连,问是否存在一条能连通所有单词的通路。典型判断欧拉道路是否存在。
判断欧拉通路条件是,图首先是连通的,无向图里面,最多有两个点度数为奇数,有向图是入读等于出度,最多有两个点,一个点入度比出度大一,另一个点出度比入度大一。
这题判断图连通性,可以选择并查集或者dfs.
并查集
#include<bits/stdc++.h>
using namespace std;
int f[1100],v[1100],n,in[1100],out[1100];
void init()
{
for(int i=0;i<26;i++){
f[i]=i;
}
}
int Find(int x)
{
if(x==f[x]) return x;
else return f[x]=Find(f[x]);
}
void Merge(int x,int y)
{
x=Find(x);y=Find(y);
if(x!=y){
f[x]=y;
}
}
int main()
{
int T,flag;cin>>T;
while(T--){
init();
flag=1;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
cin>>n;
for(int i=0;i<n;i++){
string a;cin>>a;
Merge(a[0]-'a',a[a.size()-1]-'a');
in[a[0]-'a']++;
out[a[a.size()-1]-'a']++;
}
int cnt=0;
for(int i=0;i<26;i++){
if((in[i]||out[i])&&f[i]==i)
cnt++;
}
if(cnt>1) flag=0;
int num1=0,num2=0;
for(int i=0;i<26;i++){
if(in[i]!=out[i]){
if(in[i]==out[i]+1) num1++;
else if(in[i]+1==out[i]) num2++;
else {flag=0;break;}
}
}
if(num1+num2>2||num1>1||num2>1||num1!=num2) flag=0;
if(flag) cout<<"Ordering is possible."<<endl;
else cout<<"The door cannot be opened."<<endl;
}
}
dfs
#include<bits/stdc++.h>
using namespace std;
int G[30][30],in[30],out[30],vis[30];
void dfs(int v)
{
vis[v]=1;
for(int i=0;i<26;i++){
if(G[v][i]&&!vis[i]){
dfs(i);
}
}
}
int main()
{
int T;cin>>T;
while(T--){
int flag=1;
memset(G,0,sizeof(G));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
int n;cin>>n;
for(int i=0;i<n;i++){
string s;cin>>s;
int a=s[0]-'a',b=s[s.size()-1]-'a';
G[a][b]=1;
in[a]++;
out[b]++;
}
int num1=0,num2=0;
for(int i=0;i<26;i++){
if(in[i]!=out[i]){
if(in[i]==out[i]+1) num1++;
else if(in[i]+1==out[i]) num2++;
else {flag=0;break;}
}
}
if(num1+num2>2||num1>1||num2>1||num1!=num2) flag=0;
if(flag){
int flag2=1;
memset(vis,0,sizeof(vis));
for(int i=0;i<26;i++){
if(in[i]) {dfs(i);break;}
}
for(int i=0;i<26;i++){
if((in[i]||out[i])&&!vis[i]) {flag2=0;break;}
}
if(flag2) cout<<"Ordering is possible."<<endl;
else cout<<"The door cannot be opened."<<endl;
}
else cout<<"The door cannot be opened."<<endl;
}
}