1. 程式人生 > >Play on Words(尤拉通路)

Play on Words(尤拉通路)

【題意】
輸入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; }