UVa 10129 - Play on Words(DFS判连通+欧拉回路)

给出n个单词,问能否将这n个单词连成串,使得每个单词最后一个字母和下个单词第一个字母相同。

首先对单词预处理,变为从首字母到最后一个字母的有向边,将单词集合变为有向图。

然后统计每个点的入度和出度,至多有两个点出度和入度不相等,且一点出度比入度大1,另一点入度比出度大1。

再判断连通性,所有出现过的单词必须连通。

满足以上条件即能连成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
const int maxn=30;
int n,inp[maxn],outp[maxn];
bool k,vis[maxn],g[maxn][maxn];
void dfs(int u){//判连通。
vis[u]=false;
for (int v=0;v<26;v++)
if (vis[v]&&g[u][v]) dfs(v);
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n;
memset(inp,0,sizeof(inp));
memset(outp,0,sizeof(outp));
memset(vis,0,sizeof(vis));
memset(g,0,sizeof(g));
k=true;
string s;
for(int i=0;i<n;i++){
cin>>s;
inp[s[0]-'a']++;
outp[s[s.size()-1]-'a']++;
vis[s[0]-'a']=vis[s[s.size()-1]-'a']=true;//预处理。
g[s[0]-'a'][s[s.size()-1]-'a']=true;
}
int cnt1=0,cnt2=0,sta=s[0]-'a';
for(int i=0;i<26;i++){//统计每个点的出度和入度。
if(!k) break;
inp[i]-=outp[i];
if(inp[i]!=0){
if(inp[i]==1){
cnt1++;
sta=i;
}
else if(inp[i]==-1) cnt2++;
else k=false;
}
}
if(cnt1>1||cnt2>1) k=false;
dfs(sta);
for(int i=0;i<26;i++){
if(!k) break;
if(vis[i]) k=false;
}
if(k) cout<<"Ordering is possible."<<endl;
else cout<<"The door cannot be opened."<<endl;
}
return 0;
}

** 本文迁移自我的CSDN博客,格式可能有所偏差。 **