最大权森林 poj 3723

Description

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

Source

 
题意就是部队要征召n个男兵和m个女兵,这些人之间按编号存在r种关系,关系值越大,那么招募过来需要的钱就越少10000-亲密度就是所需要的钱,要你按照一定的顺序招募,花的钱越少。(这个题目就很奇怪,你让别人帮你拉皮条,你反而可以少给人家钱???)总之这个题目就是求一个最大权的森林,那么就是个裸的最小生成树。只不过要么改一下生成树的顺序,变成降序,要么就把权值取反,最后加上路径和ans,这个题目有个巨坑,就是男女的编号是分开的...男女分别从0开始到n,所以要处理一下输入数据,比方说女的第一个人就是0+n,(这个坑了我半个多小时debug),还有一个坑就是输入输出,cincout会tle,我关了同步也tle,不知道为什么.... 只能scanf printf....都说关了同步还比scanf快一点嘛...
//#include <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;

#define maxn 100005
#define INF 9999999

int p[maxn],r[maxn],s,n,m,k,ans,cnt;
struct edge
{
    int x,y,z;
} mp[maxn];

void init(int n)
{
    for(int i=0; i<=n; i++)
    {
        p[i]=i;
        r[i]=0;
    }
}

int Find(int x)
{
    return p[x]==x ? x : p[x]=Find(p[x]);
}

bool cmp(const edge &a,const edge &b)
{
    return a.z<b.z;
}

void unite(int x,int y)
{
    x=Find(x);
    y=Find(y);
    if(x==y) return;
    if(r[x]<r[y])
        p[x]=y;
    else
    {
        p[y]=x;
        if(r[x]==r[y]) r[x]++;
    }
}

void kruskal()
{
    sort(mp,mp+k,cmp);
    init(s);
    ans=0;
    for(int i=0; i<k; i++)
    {
        int x=Find(mp[i].x),y=Find(mp[i].y);
        if(x==y) continue;
        ans+=mp[i].z;
        unite(x,y);
        //cnt++;
        //if(cnt==s-1) return;
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n,&m,&k);
        s=n+m;
        memset(mp,0,sizeof(mp));
        for(int i=0;i<k;i++)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            mp[i].x=a;
            mp[i].y=b+n;      //注意看题男女都是从0开始编号的,要重新编号!
            mp[i].z=-c;
        }
        kruskal();
        int sum=10000*s+ans;
        printf("%d
",sum);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/youchandaisuki/p/8660333.html