题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4313

思路:初始时一条边都不加,将所有边按权值从大到小排序,判断每一个边两端的顶点是否是均为machine节点,如果是则应删除这条边(即sum要加上这条边的权值),否则加入这条边,然后在并查集合并时尽量让根节点为machine节点。

hdu 4313(类似于kruskal)_图论hdu 4313(类似于kruskal)_i++_02
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define MAXN 100010
 7 typedef long long ll;
 8 int n,k;
 9 int parent[MAXN];
10 bool mark[MAXN];
11 struct Edge{
12    int u,v,w;
13 }edge[MAXN];
14 ll sum;
15 
16 int cmp(const Edge &p,const Edge &q){
17    return p.w>q.w;
18 }
19 
20 int Find(int x){
21    int s;
22    for(s=x;s!=parent[s];s=parent[s])
23    ;
24    while(s!=x){
25       int tmp=parent[x];
26       parent[x]=s;
27       x=tmp;
28    }
29    return s;
30 }
31 
32 void Union(int u,int v){
33    if(mark[u])parent[v]=u;
34    else if(mark[v])parent[u]=v;
35    else if(u<v)parent[v]=u;
36    else parent[u]=v;
37 }
38 
39 int main(){
40    int _case,x;
41 //   freopen("1.txt","r",stdin);
42    scanf("%d",&_case);
43    while(_case--){
44       scanf("%d%d",&n,&k);
45       for(int i=0;i<n-1;i++){
46          scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
47          parent[i]=i;
48       }
49       parent[n-1]=n-1;
50       sort(edge,edge+n-1,cmp);
51       memset(mark,false,sizeof(mark));
52       for(int i=1;i<=k;i++){ scanf("%d",&x);mark[x]=true; }
53       sum=0;
54       for(int i=0;i<n-1;i++){
55          int u=Find(edge[i].u);
56          int v=Find(edge[i].v);
57          int w=edge[i].w;
58          if(mark[u]&&mark[v]){
59             sum+=w;
60          }else
61             Union(u,v);
62       }
63       printf("%I64d\n",sum);
64    }
65    return 0;
66 }
View Code