1. 程式人生 > >【並查集】洛谷_2700 逐個擊破(平津戰役)

【並查集】洛谷_2700 逐個擊破(平津戰役)

題意

給出NN個點,它們之間有N1N-1條路徑相連,其中KK個特殊點,我們要刪去一些邊使得這KK個點不連通,求最少的刪除代價。

思路

可以想到構圖。我們刪邊的最小代價等於用總代價減去構圖的最大代價,於是我們可以把邊從大到小排序來放入並查集裡。當加入一條邊時,判斷兩個點是不是特殊點,還有特殊點的集合裡的點都要標記成特殊點,代表特殊點連到這個集合的某一個點都會與另一個特殊點連通,就不符題意。

程式碼

#include<cstdio>
#include<algorithm>

struct node{
	int x, y, z;
}e[100001];
int N, K;
long long ans; int enemy[100001], father[100001]; int cmp(node x, node y) { return x.z > y.z; } int find(int x) { return x == father[x] ? x : father[x] = find(father[x]); } int main() { scanf("%d %d", &N, &K); int x; for (int i = 1; i <= K; i++) { scanf("%d", &x); enemy[x] = 1
; } for (int i = 1; i < N; i++) { scanf("%d %d %d", &e[i].x, &e[i].y, &e[i].z); ans += e[i].z; father[i] = i; } father[N] = N; std::sort(e + 1, e + N, cmp); for (int i = 1; i < N; i++) { int f1 = find(e[i].x), f2 = find(e[i].y); if (enemy[f1] && enemy[f2]) continue
;//特殊點之間不能連通 father[f1] = f2; ans -= e[i].z; if (enemy[f1]) enemy[f2] = 1;//標記 else if (enemy[f2]) enemy[f1] = 1; } printf("%lld", ans); }