【POJ - 3723】Conscription (最大生成树,最小生成树MST变形)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/88807928

题干:

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, NM and R.
Then R lines followed, each contains three integers xiyi and di.
There is a blank line before each test case.

1 ≤ NM ≤ 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个男孩,想把她们收留成他的士兵。征兵无特权,必须交纳一万元。女孩和男孩之间有一些关系,温迪可以利用这些关系来降低他的成本。如果X女孩和Y男孩有D关系,并且其中一个已经被收集,Windy可以用10000-D人民币收集另一个。现在考虑到男孩和女孩之间的所有关系,你的任务是找到风必须支付的最少的钱。注意,收集一个士兵时只能使用一个关系。

解题报告:

  首先问题转化成:为了招到每个人 都先给每个人10000元,但是因为一些选择的关系,使得可以再还回来一些钱。

  建图,这题把R个关系转换成R条无向边,每个士兵只能用一个关系说明图中选择某些边,但是边构成的图不能有环(不难想到是棵树)。然后要还回来的钱最多,所以要选择边权最大的边来构成这棵树。于是转化成最大生成树问题,不过这里要注意不一定是选择的这棵树包含所有的顶点,因为只要是树就行呗,不一定非连通所有的顶点啊,没有连通的顶点我就付给他10000元就是了。所以最后用预付的每个人10000 减去  最大生成树的权值  就是我们支付的最少的钱了。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
int f[MAX]; 
int n,m,all,R; 
struct Edge {
	int u,v;
	ll w;
} e[MAX];
bool cmp(Edge a,Edge b) {
	return a.w > b.w;
}
int getf(int v) {
	return v == f[v] ? v : f[v] = getf(f[v]);
}
void merge(int u,int v) {
	int t1 = getf(u);
	int t2 = getf(v);
	f[t2] = t1;
}
int main()
{
	int t;
	cin>>t;
	while(t--) {
		cin>>n>>m;//n女孩  m男孩 
		all = n+m;
		for(int i = 1; i<=all; i++) f[i] = i;
		cin>>R;//R个关系 
		for(int x,y,i = 1; i<=R; i++) {
			ll d;
			scanf("%d%d%lld",&x,&y,&d);
			x++,y++;
			y+=n;
			e[i].u = x;e[i].v = y;e[i].w = d;
		}
		ll ans = 0;
		sort(e+1,e+R+1,cmp);
		for(int u,v,i = 1; i<=R; i++) {
			u = e[i].u,v = e[i].v;
			if(getf(u) != getf(v)) {
				merge(u,v);
				ans += e[i].w;
			}
		}
		printf("%lld\n",all*10000LL - ans);		
	}

	return 0 ;
}
/*
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

*/

注意转化关系,每个人的关系只能使用一次,类似的问题,可以转化成每个顶点的入度?出度?这题中是转化成不能有环的问题,其实题目中表达的不是很清晰。

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/88807928