【最大生成树】Conscription

Conscription
Time Limit: 1000MS   Memory Limit: 65536K
     

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, 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

OJ:POJ

题目大意

需要征募女兵N人,男兵M人。每征募一个人需要花费10000美元。但是如果已经征募的人中有一些关系亲密的人,那么可以少花一些钱。给出若干的男女之间的1~19999之间的亲密度关系,征募某个人的费用是1000-(已经征募的人中和自己的亲密度的最大值)。要求通过适当的征募顺序使得征募所有人所需费用最小。输入的关系中x,y,d表示第x号男兵,第y号女兵,亲密度。

分析

征募人的时候尽可能找亲密度大的,即最大生成树问题,用征募N+M人的费用减去最大生成树的总权值即所需最小费用。

参考代码

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

struct Edge{
int x;
int y;
int weight;
}edge[50001];
int par[20001];
int rank[20001];
int vertex_num,arc_num,case_num;
int N,M,R;
int ans,sum;

void init();
int find(int x);
bool unite(int x,int y);
bool compare(const Edge &a,const Edge &b);
void kruskal();

int main()
{
    scanf("%d",&case_num);
    while(case_num){
        sum=0;
        scanf("%d%d%d",&N,&M,&R);
        vertex_num=N+M;
        arc_num=R;
        for(int i=0;i<R;i++){
            scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].weight);
            edge[i].y+=N;//区别男女兵
        }
        kruskal();
        int ans=10000*vertex_num-sum;
        printf("%d
",ans);
        case_num--;
    }

    return 0;
}

void init(){
    for(int i=0;i<vertex_num;i++){
        par[i]=i;
        rank[i]=0;
    }

}

int find(int x){
if(x==par[x])
    return x;
else{
    return par[x]=find(par[x]);
}
}

bool unite(int x,int y){
int r1=find(x);
int r2=find(y);
if(r1==r2)
    return false;
else{
    if(rank[r1]>rank[r2]){
        par[r2]=r1;
    }
    else if(rank[r1]<rank[r2]){
        par[r1]=r2;
    }
    else{
        par[r2]=r1;
        rank[r1]++;
    }
    return true;

    }
}

bool compare(const Edge &a,const Edge &b){
    return a.weight>b.weight;
}

void kruskal(){
    init();
    sort(edge,edge+arc_num,compare);
    for(int i=0;i<arc_num;i++){
        if(unite(edge[i].x,edge[i].y)){
            sum+=edge[i].weight;
        }
    }
}

 

 

 

 

原文地址:https://www.cnblogs.com/LuRenJiang/p/7424194.html