--- title: "AtCoder Beginner Contest 239 F(生成樹)" tags: 題解, 資料結構, 並查集, 圖論, 生成樹 --- https://atcoder.jp/contests/abc239/tasks/abc239_f #### 題意 給一個 $N$ 個點的圖,已經建好 $M$ 條邊,並給出數列 $D$,要求再新增 $N - M - 1$ 條邊使整張圖連通,且第 $i$ 個點的 degree 須為 $D[i]$。 #### 思路 由於 $M$ 條邊再加上 $N - M - 1$ 條邊形成 $N - 1$ 條邊,又要求須為連通圖,明顯看出要讓圖變成一棵生成樹。 首先我們可以把已經連通的塊收集起來 (Union Find),根據塊中的點計算出整個塊所需新增的邊之數量,接下來就可以開始新增邊。 新增邊時只會在不同連通塊之間新增,且為了不讓某些塊無法與其他人連接,我們優先考慮那些需求為 $1$ 的連通塊,將其與剩下的塊中需求大於 $1$ 的塊相連 (若不存在則選擇需求為 $1$ 的塊也行)。如果發現連通的過程中塊數不足 $2$,或是不存在需求為 $1$ 的塊,則不可能完成生成樹。 #### Code ```python=1 def solve(): N, M = map(int, input().split()) D = list(map(int, input().split())) if sum(D) != 2 * N - 2: print(-1) return dsu = DSU(N) for _ in range(M): a, b = map(int, input().split()) a -= 1; b -= 1 D[a] -= 1; D[b] -= 1 if not dsu.union(a, b) or D[a] < 0 or D[b] < 0: print(-1) return deq = deque() for (_, grp) in dsu.all_groups().items(): tot_need = 0 needs = [] for node in grp: if D[node]: tot_need += D[node] needs.append([node, D[node]]) if tot_need > 1: deq.append([tot_need, needs]) elif tot_need == 1: deq.appendleft([tot_need, needs]) ans = [] for _ in range(N - M - 1): if len(deq) < 2 or deq[0][0] != 1: print(-1) return grp1 = deq.popleft() grp2 = deq.pop() ans.append(str(grp1[1][-1][0] + 1) + " " + str(grp2[1][-1][0] + 1)) for grp in (grp1, grp2): if grp[1][-1][1] == 1: grp[1].pop() else: grp[1][-1][1] -= 1 grp[0] -= 1 if grp[0] > 1: deq.append(grp) elif grp[0] == 1: deq.appendleft(grp) print(*ans, sep="\n") if __name__ == "__main__": solve() ```