您的位置:首页 > 其它

HDU 4313 Matrix (贪心+并查集)

2015-02-17 23:52 471 查看
题意:给你一个有n(2<=n<=100000)个节点的树,树中每条边都有一个权值。然后再给你k(2<=k<=n)个点,表示这些点上有一个机器人。最后让你删去一些边使任意两个机器人都不能互达,且所删边的权值之和要最小。

思路:

正着思考的确不好入手,反着思考,让机器人不能互达,所以独立成一个集合,可以用并查集,然后模拟加边,若加上的边让机器人互连那么就删去这条边,可见,让删去的边越短越好,所以尽可能先添加长边。

//2776 KB	218 ms
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
    int u,v,w;
}edge[100100];
bool cmp(const node &a,const node&b)
{
    return a.w>b.w;
}
int n,k;
bool book[100100]; //标记有机器人的城市 
int f[100100];
int getf(int x)
{
    return x==f[x]? x:f[x]=getf(f[x]);
}
void unite(int x,int y)
{
    f[x]=y; // 因为原图是树,所以肯定不在同一个集合,直接合并 
    if(book[x]||book[y]){
        book[y]=true;
    }
}
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--){
        long long ans=0;
        memset(book,0,sizeof(book));
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++) f[i]=i;
        for(int i=1;i<n;i++){
            int a,b,w;
            scanf("%d%d%d",&a,&b,&w);
            edge[i].u=a;
            edge[i].v=b;
            edge[i].w=w;
        }
        for(int i=1;i<=k;i++){
            int tmp;
            scanf("%d",&tmp);
            book[tmp]=true;
        }
        sort(edge+1,edge+n,cmp);
        for(int i=1;i<n;i++){
            int &u=edge[i].u,&v=edge[i].v,&w=edge[i].w;
            int x=getf(u),y=getf(v);
            if(book[x]&&book[y]){
                ans+=w;
                continue;
            }
            unite(x,y);
        }
        printf("%I64d\n",ans);

    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: