POJ, 3723 Conscription(最小生成树)

来源:互联网 发布:剑道眼镜知乎 编辑:程序博客网 时间:2024/06/07 13:54

题意:征女兵n人,男兵m人。每征兵一个人话费10000美元,如果已经征的人中有关系亲密的人,征另外的人是10000减去亲密度,求最少费用。

分析:建立森林,边的权值为亲密度的相反数,然后用最小生成树连接所有点,得到可以节约的最大费用(是负数),结果也就出来了。







#include <iostream>#include<vector>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;#define N 50005struct edge{   int u,v,cost;   bool operator<(const edge &a)const   {       return cost<a.cost;   }};edge es[N];int m,n,r;int par[N],myrank[N];void init(int n){    for(int i=0;i<n;i++)    {        par[i]=i;    }    memset(myrank,0,sizeof(myrank));}int myfind(int x){    if(x==par[x])        return x;    return par[x]=myfind(par[x]);}void unite(int x,int y){    x=myfind(x);    y=myfind(y);    if(x==y)        return ;    if(myrank[x]>myrank[y])       {           par[y]=x;       }        else        {            par[x]=y;            if(myrank[x]==myrank[y])            {               myrank[y]++;            }        }}bool same(int x,int y){    return myfind(x)==myfind(y);}int kruskal(){    sort(es,es+r);    init(m+n);    int res=0;    for(int i=0;i<r;i++)    {        edge e=es[i];        if(!same(e.u,e.v)){            unite(e.v,e.u);        res+=e.cost;        }    }    return res;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d%d%d",&n,&m,&r);        init(n+m);        for(int i=0;i<r;i++){        scanf("%d%d%d",&es[i].u,&es[i].v,&es[i].cost);        es[i].v+=n;        es[i].cost=-es[i].cost;        }       printf("%d\n", 10000*(m+n)+kruskal());    }    return 0;}


0 0
原创粉丝点击