POJ 3723 Conscription(最小生成树)
Windy has a country, and he wants to build an army to protect his country. He has picked up N girls and M boys and wants to collect them to be his soldiers. To collect a soldier without any privilege, he must pay 10000 RMB. There are some relationships between girls and boys and Windy can use these relationships to reduce his cost. If girl x and boy y have a relationship d and one of them has been collected, Windy can collect the other one with 10000-d RMB. Now given all the relationships between girls and boys, your assignment is to find the least amount of money Windy has to pay. Notice that only one relationship can be used when collecting one soldier.
Input
The first line of input is the number of test case.
The first line of each test case contains three integers, N, M and R.
Then R lines followed, each contains three integers xi, yi and di.
There is a blank line before each test case.
1 ≤ N, M ≤ 10000
0 ≤ R ≤ 50,000
0 ≤ xi < N
0 ≤ yi < M
0 < di < 10000
Output
For each test case output the answer in a single line.
Sample Input
2
5 5 8
4 3 6831
1 3 4583
0 0 6592
0 1 3063
3 3 4975
1 3 2049
4 2 2104
2 2 781
5 5 10
2 4 9820
3 2 6236
3 1 8864
2 4 8326
2 0 5156
2 0 1463
4 1 2439
0 4 4373
3 4 8889
2 4 3133
Sample Output
71071
54223
题意:
Windy有一个国家,他想建立一个军队来保护他的国家。 他召集了N个女孩和M男孩,想把他们雇佣成为他的士兵。 要无偿雇佣士兵,必须支付10000元。 女孩和男孩之间有一些关系,而Windy可以利用这些关系来降低他的成本。 如果女孩x和男孩y有关系,并且其中一个已经被收集,Windy可以以10000-d的价格收集另一个。 现在给予女孩和男孩之间的所有关系,你的任务是找到Windy必须支付的最少的钱。
题解:
看清题意,这个题是求解图的最大权森林问题,然后可以通过把所有边权取反之后用最小生成树来求解。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=2e4+5;
int par[maxn];
struct edge
{
int u,v,cost;
bool operator <(const edge &a) const
{
return cost<a.cost;
}
}es[50005];
int n,m,r;
void init()
{
for(int i=0;i<n+m;i++)
par[i]=i;
}
int find(int x)
{
return par[x]==x?x:par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
par[x]=y;
}
bool same(int x,int y)
{
return find(x)==find(y);
}
void Kruskal()
{
init();
sort(es,es+r);
int res=0;
for(int i=0;i<r;i++)
{
edge e=es[i];
if(!same(e.u,e.v))
{
unite(e.u,e.v);
res+=e.cost;
}
}
printf("%d\n",10000*(n+m)+res);
}
int main()
{
//ios::sync_with_stdio(false);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&r);
for(int i=0;i<r;i++)
{
int u,v,cost;
scanf("%d%d%d",&u,&v,&cost);
es[i]=(edge){u,v+n,-cost};
}
Kruskal();
}
return 0;
}