题意:征女兵n人,男兵m人。每征兵一个人话费10000美元,如果已经征的人中有关系亲密的人,征另外的人是10000减去亲密度,求最少费用。
分析:建立森林,边的权值为亲密度的相反数,然后用最小生成树连接所有点,得到可以节约的最大费用(是负数),结果也就出来了。
#include <iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 50005
struct 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;
}