題目地址:
題目分析:
n個單詞形成序列,能夠使每一個單詞的第一個字母和上一個單詞的最後一個字母相同,即是否形成歐拉通路,所以先以每個單詞的首、尾形成點,連成有向邊構圖。但需要注意的是:只能存在一個歐拉通路(即一個聯通集)!這可以通過遞歸完一次dfs搜索後,再一次掃描所有單詞,判斷是否還存在沒有訪問到的邊。
代碼如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100;
int T, n, G[maxn][maxn], c[maxn], in[maxn], out[maxn];
int vis[maxn]; //判斷邊的關係
char s[1010];
void read_word(){
for(int i = 0;i < n;i++){
scanf("%s",s);
int len = strlen(s);
int r = s[0] - 'a'; //首字母
int t = s[len - 1] - 'a'; //尾字母
G[r][t] = 1; //記錄邊的關係
out[r]++;in[t]++;
vis[r] = vis[t] = 0; //設置爲未訪問狀態
}
}
void dfs(int u){
vis[u] = 1; //設置爲訪問狀態
for(int v = 0; v < 26;v++)
if(!vis[v] && G[u][v]) dfs(v); //遞歸尋找所有u的子孫
}
int main(void){
//freopen("data.out","w",stdout);
scanf("%d",&T);
while(T--){
memset(vis,-1,sizeof(vis));
memset(G,0,sizeof(G));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
scanf("%d",&n);
read_word();
int p = 0, begin = 0, tail = 0, cnt = 0;
int flag = 0;
for(int i = 0;i < 26;i++){
if(out[i] == in[i]){ //中間節點,則跳過下面的步驟
continue;
}
if(out[i] == in[i] + 1){ //是起始點
begin++;p = i;
} else if(in[i] == out[i] + 1) //終止點
tail++;
else
cnt++; //入度不等於出度,並且不爲起始點或者終止點
}
if(cnt > 0){ //如果個別節點
cout<<"The door cannot be opened.\n";
continue;
}
if(begin == 1 && tail == 1 || begin == 0 && tail == 0) //有一個奇度起點與終點,或者全部爲偶數度頂點
flag = 1;
else
flag = 0;
dfs(p); //dfs返回後掃描完了一個聯通集
//掃描所有字母,判斷只有一個聯通集
for(int i = 0;i < 26;i++){
if(!vis[i]) flag = 0; //如果還有未訪問的聯通集
}
if(flag) cout<<"Ordering is possible.\n";
else cout<<"The door cannot be opened.\n";
}
return 0;
}