1. 程式人生 > >2012 Multi-University Training Contest 2

2012 Multi-University Training Contest 2

clu amp roo while edge set %d \n --

HDU-4314

題意:給定一棵樹,每條邊有權值,要求刪邊使得樹分為k個部分,有k個特殊的節點,要使這k個節點在不同的部分,求刪除的邊的最小權值和

題解:邊從大到小排序,並查集維護,如果該條邊的兩個頂點所在的集合有特殊點,則刪除這條邊,如果只有一個特殊點,合並且讓特殊點作為根節點

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

struct Edge{
    int u, v, next;
    
long long w; }edge[200010]; int head[100010], cnt; int vis[100010]; int n, k; int fa[100010]; int Find(int x){ return x == fa[x]?x:fa[x] = Find(fa[x]); } void init(){ memset(head, -1, sizeof(head)); memset(vis, 0, sizeof(vis)); cnt = 0; for(int i = 0; i<=n; i++) fa[i] = i; } void add(int u, int
v, long long w){ edge[cnt].u = u; edge[cnt].v = v; edge[cnt].w = w; edge[cnt].next = head[u]; head[u] = cnt++; } bool cmp(Edge a, Edge b){ return a.w>b.w; } int main(){ int T; scanf("%d", &T); while(T--){ scanf("%d %d", &n, &k); init();
for(int i = 1; i<=n-1; i++){ int x, y; long long z; scanf("%d %d %lld", &x, &y, &z); add(x, y, z); //add(y, x, z); } for(int i = 1; i<=k; i++){ int x; scanf("%d", &x); vis[x] = 1; } sort(edge, edge+(n-1), cmp); long long ans = 0; int num = 1; for(int i = 0; i<n-1; i++){ int a = edge[i].u, b = edge[i].v; int roota = Find(a), rootb = Find(b); if(vis[roota] == 1 && vis[rootb] == 1){ ans += edge[i].w; num++; } if(vis[roota] == 1 && vis[rootb]!=1){ fa[rootb] = roota; } if(vis[rootb] == 1 && vis[roota]!=1){ fa[roota] = rootb; } if(vis[roota] != 1 && vis[rootb]!=1){ fa[rootb] = roota; } if(num == k) break; } printf("%lld\n", ans); } return 0; }

2012 Multi-University Training Contest 2