给出n个单词, 是否可以把所有单词排成一个首尾相连的排序。
典型的欧拉道路的题, 把字母当成结点,然后判断是否为欧拉道路。
欧拉道路存在的两个条件:
1.最多只能有两个结点的入度不等于出度,两点有一点的入度 - 出度 = 1,此为起点, 另一点出度 - 入度 = 1, 此为终点。另外就是每个点的入度等于出度。
2.忽略方向得到的地图连通。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
using namespace std;
const int maxn = 26 + 7;
struct Word{
int in, out;
};
int k, n, cnt;
int G[maxn][maxn];
int visited[maxn];
Word word[maxn];
void init() {
for(int i = 0; i < 26; ++i) {
word[i].in = word[i].out = 0;
}
}
bool dfs(int u, int k) {
if(k == cnt) return true;
for(int v = 0; v < 26; v++) {
if (visited[v] == 1 && G[u][v]) {
visited[v] = -1;
return dfs(v, k + 1);
}
}
return false;
}
int main() {
int T, cnt_in, cnt_out;
bool ok1, ok2, cannt;
string t;
cin >> T;
while(T--) {
cnt = cnt_in = cnt_out = 0;
ok1 = ok2 = cannt = false;
init();
memset(G, 0, sizeof(G));
memset(visited, 0, sizeof(visited));
cin >> n;
for(int i = 0; i < n; i++) {
cin >> t;
G[t[0] - 'a'][t[t.size() - 1] - 'a'] = G[t[t.size() - 1] - 'a'][t[0] - 'a'] = 1;
if(!visited[t[0] - 'a']) cnt++;
visited[t[0] - 'a'] = 1;
if(!visited[t[t.size() - 1] - 'a']) cnt++;
visited[t[t.size() - 1] - 'a'] = 1;
++word[t[0] - 'a'].in;
++word[t[t.size() - 1] - 'a'].out;
}
for(int i = 0; i < 26; i++) {
if(word[i].in - word[i].out > 1) cannt = true;
else if(word[i].in - word[i].out < -1) cannt = true;
if(word[i].in - word[i].out == 1) ++cnt_in;
else if(word[i].in - word[i].out == -1) ++cnt_out;
}
if(!cannt)
if((cnt_in == 1 && cnt_out == 1) ||
(cnt_in == 0 && cnt_out == 0)) ok1 = true;
if(ok1 && !cannt) {
for(int i = 0; i < 26; i++) {
if(visited[i] == 1) {
visited[i] = -1;
ok2 = dfs(i, 1);
break;
}
}
}
if(ok1 && ok2 && !cannt) cout << "Ordering is possible." << endl;
else cout << "The door cannot be opened." << endl;
}
return 0;
}