POJ3723 Conscription 【并检查集合】

Conscription

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 8071   Accepted: 2810

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

POJ Monthly Contest – 2009.04.05, windy7926778

题意:有N个女孩M个男孩去报名,每一个人报名花费10000,可是假设未报名的小孩跟已报名的小孩中有关系亲热的异性,那么能够少花一些钱。

给出若干男女关系之间的1~9999亲热度,报名费用为10000-(已报名的人中跟自己亲热度的最大值)。求全部人的报名费用和的最小值。

题解:不能由于看到男女关系就朝二分图想,实际上这题用的是最小生成树思想。虽然最后的结果可能是森林,仅仅需让ans+=森林个数*10000;

#include <stdio.h>
#include <string.h>
#include <algorithm>

#define maxn 20010
#define maxm 100010
#define COST 10000

int N, M, R, id;
int pre[maxn];
struct Node {
    int u, v, w;
} E[maxm];

bool cmp(Node a, Node b) {
    return a.w < b.w;
}

void addEdge(int u, int v, int w) {
    E[id].u = u; E[id].v = v; E[id++].w = w;
}

void getMap() {
    int x, y, d; id = 0;
    while(R--) {
        scanf("%d%d%d", &x, &y, &d);
        addEdge(x, y + N, COST - d);
    }
}

int ufind(int k) {
    int a = k, b;
    while(pre[k] != -1) k = pre[k];
    while(a != k) {
        b = pre[a];
        pre[a] = k;
        a = b;
    }
    return k;
}

bool same(int x, int y) {
    return ufind(x) == ufind(y);
}

void unite(int x, int y) {
    x = ufind(x);
    y = ufind(y);
    if(x != y) pre[y] = x;
}

void Kruskal() {
    int cnt = N + M, i, x, y, ans = 0;
    memset(pre, -1, sizeof(int) * (N + M));
    std::sort(E, E + id, cmp);
    for(i = 0; i < id; ++i) {
        if(!same(E[i].u, E[i].v)) {
            unite(E[i].u, E[i].v);
            ans += E[i].w;
            if(--cnt == 1) break;
        }
    }
    printf("%d\n", ans + COST * cnt);
}

int main() {
    // freopen("stdin.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d%d", &N, &M, &R); // G B
        getMap();
        Kruskal();
    }
    return 0;
}

版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 2024-10-17 19:46:50

POJ3723 Conscription 【并检查集合】的相关文章

POJ3723 Conscription

PS: 分析这是一道不错的题目,要求去抽象. 直接说结论: 题目可能是许森林,每一个森林有一颗最小生成树并且选择第一个点花费为10000. 这道题目实现的时候我对0 ~ M进行了编码为 N 到 M+N-1. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; cons

URAL - 1966 - Cycling Roads(并检查集合 + 判刑线相交)

意甲冠军:n 积分,m 边缘(1 ≤ m < n ≤ 200),问:是否所有的点连接(两个边相交.该 4 点连接). 主题链接:http://acm.timus.ru/problem.aspx?space=1&num=1966 -->>对于每条边,边上的两端点并入集合,枚举边与边.推断他们是否相交,是的话各点并入集合,最后看集合内元素的个数是否为n.. #include <cstdio> #include <cmath> const int MAXN =

hdu1325 Is It A Tree?并检查集合

pid=1325">职务地址 试想一下,在词和话题hdu1272是一样的. 可是hdu1272的博文中我也说了.数据比較水,所以我用非并查集的方法就AC了. 可是这题的数据没那么水,要用到并查集来解.这题的盲点和重点有这么几个: 输入不是以-1 -1结束,而是以两个负数结束 须要用并查集来推断是不是仅仅有一个"根" 须要推断全部节点的入度是否大于1 本题输入的格式.也要注意一下. 能够先忽略图中的方向的.由于假设有环的话,就变成图了.若严格的依照用parent数组来保存

《算法导论》2.3-7 检查集合中是否存在两数字和为指定的X--算法和证明

习题2.3-7:设计一个算法,对于一个给定的包含n个整数的集合S和另一个给定的整数X,该算法可以在时间内确定S中是否存在两个元素,使得它们的和恰为X. 解题思路:首先应该想到的是先用一个的排序算法对S中的元素进行排序.接下来有两种处理思路,第一种思路是遍历已经排好序了的S中的所有元素a,并采用 二分查找的方法在S中查找X-a,如果能够找到,那么说明S中确实存在两个元素的和为X,算法终止.这种思路很显然是满足的限制要求的:第二种思路是我自己 想出的一个算法,这个算法也很简单,但是其正确性不是很好证

POJ3723 Conscription 【并查集】

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

普林斯顿大学公开课 算法1-10:并检查集合-高速整合方法优化

本节介绍了高速综合优化算法. 重量的概念,每次操作的时候将重量小的部件挂在重量大的部件之下. 这样就避免了树形结构太高的问题. 下图展示了优化前后的树形结构深度的对照. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FpcGVpY2hhbzI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > 证明 能够证明每一个节点的深度最大为lgN. 由于

poj 2513 Colored Sticks(欧拉路径+并检查集合+特里)

题目链接:poj 2513 Colored Sticks 题目大意:有N个木棍,每根木棍两端被涂上颜色.如今给定每一个木棍两端的颜色.不同木棍之间拼接须要颜色同样的 端才干够.问最后是否能将N个木棍拼接在一起. 解题思路:欧拉通路+并查集+字典树. 欧拉通路,每一个节点的统计度,度为奇数的点不能超过2个.并查集,推断节点 是否全然联通. 字典树,映射颜色. #include <cstdio> #include <cstring> #include <string> #i

BZOJ 1015 JSOI2008 星球大战 starwar 并检查集合

标题效果:给定一个无向图.联通谋求块的数目,以及k一个点的破坏后每次:联通,块的数目 侧面和摧毁的地步全记录,我们可以做相反的. 需要注意的是该点不能算作破坏联通块 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 400400 using namespace std; struct abcd{ int to,next; }table[M];

BZOJ 3211 弗洛拉前往国家 树阵+并检查集合

标题效果:给定一个序列,它提供了以下操作: 1.将[l.r]每个号码间隔a[i]变sqrt(a[i]) 2.查询[l,r]间隔和 剧烈的变化不支持由间隔,因此,我们选择单 - 点更换间隔查询的树阵,但是,这是O(n^2)的,怎么办? 我们发现一个数x最多开loglogx次根号就会变为1 也就是一个int范围内的数仅仅要开6次根号就会变为1 于是改动的总时间复杂度为O(nloglogn) 可是单次改动怎么办?我们维护一个并查集.一旦一个数为1或0,我们就把这个位置的father设为它右面的那个位置