题目地址:
题目分析:
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;
}