题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4313
思路:初始时一条边都不加,将所有边按权值从大到小排序,判断每一个边两端的顶点是否是均为machine节点,如果是则应删除这条边(即sum要加上这条边的权值),否则加入这条边,然后在并查集合并时尽量让根节点为machine节点。
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 }