1. 程式人生 > >POJ 3723 Conscription(最小生成樹)

POJ 3723 Conscription(最小生成樹)

protect pic print script ++ have pac been algo

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;
}

POJ 3723 Conscription(最小生成樹)