题目:http://poj.org/problem?id=3723

Conscription
Time Limit: 1000MS		Memory Limit: 65536K
Total Submissions: 24785		Accepted: 8280
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

这题乍一看没想出该怎么做,看了书才明白。首先肯定是先建图啦!然后因为要求最小花费,而每个人的花费是10000-(已征募的人中和自己亲密度的最大值)。而亲密度是已经给出的,且亲密度越大,花费越少。

转换为最小生成树问题

只要我们把亲密度都取负数,再求最小生成树,就能得出最小的花费了。由于这个图不一定是连通的,我们实际上是对不同的连通分量求最小生成树。因此我们采用Kruskal算法求解最小生成树。

AC代码:

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;

#define MAXN 10005
typedef long long ll;
struct edge
{
    int from, to, cost;
} e[5 * MAXN];

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

int fa[3*MAXN];
int height[3*MAXN];
int n, m, r;

//初始化并查集
void init_ufs(int sz)
{
    for (int i = 0; i <= sz; ++i)
        fa[i] = i;

    memset(height, 0, sizeof(height));
}

int find_set(const int x)
{
    
    if (fa[x] == x)
        return x;

    fa[x] = find_set(fa[x]);
    return fa[x];
    
}

bool same(const int &a, const int &b)
{
    return find_set(a) == find_set(b);
}

void unite(int a, int b)
{
    a = find_set(a);
    b = find_set(b);
    if (a != b)
    {
        if (height[a] < height[b])
        {
            fa[a] = b;
        }
        else
        {
            fa[b] = a;
            if (height[a] == height[b])
                ++height[a];
        }
    }
}

int kruskal()
{
    sort(e, e + r, cmp);
    init_ufs(n+m);

    int ans = 0;
    for (int i = 0; i < r; ++i)
    {
        if (!same(e[i].from, e[i].to))
        {
            //cout<<e[i].from<<" "<<e[i].to<<endl;
            unite(e[i].from, e[i].to);
            ans += e[i].cost;
        }
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d%d", &n, &m, &r);
        int xi, yi, di;
        for (int i = 0; i < r; ++i)
        {
            scanf("%d%d%d", &xi, &yi, &di);
            //e[i] = (edge){xi, yi + n, -di};
            e[i].from = xi;
            e[i].to = yi+n;
            e[i].cost = -di;
        }
        printf("%lld\n", 10000ll * (m + n) + kruskal());
    }
}

转载请注明来源:https://www.longjin666.top/?p=1140

欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~

你也可能喜欢

发表评论