Play on Words(尤拉通路)
阿新 • • 發佈:2019-01-28
【題意】
輸入n(n<=100000)個單詞,是否可以把所有這些單詞排成一個序列,使得每個單詞的第一個字母和上一個單詞的最後一個字母相同(如acm,malform,mouse)每個單詞最多包含1000個字母,輸入中可以有重複單詞。
【思路】
紫書169頁例題,把每一個單詞的首字母看作起點,尾字母看作終點,做一條有向邊,則該題目就是問圖中有無歐拉回路或尤拉通路的問題。有向圖中,首先要滿足在忽略邊的方向後圖是聯通的,通過dfs判斷,其次歐拉回路存在的條件是所有頂點的出度等於入度,尤拉通路存在的條件是隻有兩個頂點的入度和出度不想等,且一個的入度=出度+1,另一個出度=入度+1
#include<bits/stdc++.h>
using namespace std;
const int maxl = 1050;
int n;
char s[maxl];
bool used[26];//記錄一下當前的圖用到了哪些結點
bool vis[26];//訪問標記
int g[26][26];//鄰接矩陣
int inDegree[26], outDegree[26];//入度,出度
void init() {
memset(g, 0, sizeof(g));
memset(vis, 0, sizeof(vis));
memset(used, 0, sizeof (used));
memset(inDegree, 0, sizeof(inDegree));
memset(outDegree, 0, sizeof(outDegree));
}
void dfs(int u) {
vis[u] = 1;
for (int i = 0; i < 26; ++i) {
if (!vis[i] && g[u][i]) dfs(i);
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
init();
scanf ("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%s", s);
int from = s[0] - 'a';
int to = s[strlen(s) - 1] - 'a';
used[from] = used[to] = 1;
g[from][to] = g[to][from] = 1;//構建的是無向圖,在忽略邊的方向後聯通即可
++inDegree[to];
++outDegree[from];
}
//判聯通
int cnt = 0;
for (int i = 0; i < 26; ++i) {
if (!vis[i] && used[i]) {
++cnt;
dfs(i);
}
}
if (cnt > 1) {
printf("The door cannot be opened.\n");
continue;
}
//判斷入度,出度的關係
bool ok = 1;
int c1 = 0, c2 = 0;
for (int i = 0; i < 26; ++i) {
if (used[i]) {
if (inDegree[i] == outDegree[i] + 1) ++c1;
else if (outDegree[i] == inDegree[i] + 1) ++c2;
else if (inDegree[i] != outDegree[i]) { ok = 0; break; }
}
}
if (!ok) {
printf("The door cannot be opened.\n");
continue;
}
if ((c1 == 0 && c2 == 0) || (c1 == 1 && c2 == 1))
printf("Ordering is possible.\n");
else
printf("The door cannot be opened.\n");
}
return 0;
}