c131: 00615 - Is It A Tree?

Tags: graph, tree


出處:https://zerojudge.tw/ShowProblem?problemid=c131
提交:https://zerojudge.tw/Submissions?problemid=c131&account=allllllan123456


問題:給定一些構成目標圖的有向邊,目標圖的頂點必須存在於至少一條有向邊才會存在,換言之我們不用考慮孤立點的問題,請問這張目標圖是否符合一棵樹的定義?一棵樹可以沒有任何頂點與邊,否則:

  1. 只能有一個頂點,我們稱之為根頂點 (root),完全沒有邊指向他。
  2. 只要不是 root,都只能剛好有一條邊指向它。
  3. 從 root 到任何一個頂點都只能有一條唯一的路徑。

解法:網路上很多解法都有提到要檢查有沒有環,其實不然。對於一張非空的圖,我們可以在輸入有向邊的時候就記錄每個頂點的上/下游頂點,如果已經有上游頂點的人又再度被指派另一個上游頂點,則違反條件 2. 直接判斷失敗,所以在有向邊輸入完畢的時候每人至多只會有一個上游頂點。現在重新檢查每個頂點的上游,確認無上游頂點是否剛好只有一個,如果不是則違反條件 1. 直接判斷失敗,否則指派該唯一頂點為 root,到這裡就確定至少滿足條件 1. 2. 了。注意到如果要違反條件 3.,也就是有至少兩條路徑可以從 root 到某特定頂點,那至少要有一個頂點有兩個以上的上游頂點才能達到,這已經違反條件 2.,因此從 root 到任何一個頂點至多就只會有一條路徑可以到達;但還有一種狀況也違反條件 3. 就是有頂點可能無法從 root 抵達,要檢查這些頂點的存在只要從 root 跑一次 DFS 看看有沒有人無法被碰觸到即可。


 1#include <bits/stdc++.h>
 2using namespace std;
 3
 4bool visit[100];
 5vector<int> adj[100];
 6
 7void dfs(int v) {
 8    visit[v] = true;
 9    for (auto u: adj[v])
10        dfs(u);
11}
12
13int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); // IO 優化
14    int a, b, root=0, T=0, parent[100]={0};
15    bool fail = false; map<int, int> m;
16    while (cin >> a >> b && !(a<0 && b<0)) {
17        if (!a && !b) {
18            if (!fail)
19                for (int i=1; i<=m.size(); i++)
20                    if (!parent[i]) {
21                        if (!root) root = i;
22                        else { fail = true; break; }
23                    }
24            if (!root && !m.empty()) fail = true;
25            if (!fail) {
26                dfs(root);
27                for (int i=1; i<=m.size(); i++)
28                    if (!visit[i])
29                        { fail = true; break; }
30            }
31            cout << "Case " << (++T) << " is " << (fail ? "not " : "") << "a tree.\n";
32            fail = false; root = 0; m.clear();
33            memset(visit, false, sizeof visit);
34            memset(parent, 0, sizeof parent);
35            for (int i=1; i<100; i++) adj[i].clear();
36            continue;
37        } else {
38            if (fail) continue;
39            try { m.at(a); } catch (...) { m[a] = m.size() + 1; }
40            try { m.at(b); } catch (...) { m[b] = m.size() + 1; }
41            adj[m[a]].push_back(m[b]);
42            if (parent[m[b]]) fail = true;
43            parent[m[b]] = m[a];
44        }
45    }
46    return 0;
47}

no image