POJ 3723 Conscription

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

这道题 把男生画一边 女生画一边 ---->是一个二部图的结构

就很容易看出

要pay最少 实际上就是找到一个连接所有点权值和最大的图 

但是又要求 一个人只能使用一种关系减钱 所以不能有回路 ---->是一棵树

所以就是求最大生成树

有了前面并查集题目的经验 我们可以让i < N为女生 i >=N 作为男生 来维持这个并查集 

那么就自然的使用Kruskal即可

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 #define MAXV 20007
 6 #define MAXE 100007
 7 #define INF 0x3f3f3f3f
 8 using namespace std;
 9 
10 struct Edge
11 {
12     int from, to, cost;
13     Edge () {}
14     Edge (int from, int to, int cost) : from(from), to(to), cost(cost) {}
15 }edge[MAXE];
16 int num = 0;
17 int par[MAXV];
18 int find(int x)
19 {
20     if (par[x] == x) return x;
21     else return par[x] = find(par[x]);
22 }
23 void unite(int x, int y)
24 {
25     int px = find(x), py = find(y);
26     if (px == py) return;
27     par[py] = px;
28 }
29 bool same(int x, int y)
30 {
31     int px = find(x), py = find(y);
32     return px == py;
33 }
34 
35 bool cmp(Edge e1, Edge e2)
36 {
37     return e1.cost > e2.cost;
38 }
39 //主要就是画图 发现其实就是不能有回路 那就是最小生成树 偶不 最大生成树
40 //书上提醒 在这个问题中 完全没有用到男女之间的二分图结构 但是在许多问题中 有特殊地结构 往往要考虑如何利用这个结构
41 //也有像本题一样设置无用陷阱条件的题目!!
42 int Kruskal()
43 {
44     int res = 0;
45     sort(edge, edge+num, cmp);
46     for (int i = 0; i < num; i++)
47     {
48         Edge e = edge[i];
49         if (!same(e.from, e.to))
50         {
51             res += e.cost;
52             unite(e.from, e.to);
53         }
54     }
55     return res;
56 }
57 
58 int main()
59 {
60     int R, N, M, T;
61     freopen("in.txt", "r", stdin);
62     scanf("%d", &T);
63     while (T--)
64     {
65         scanf("%d%d%d", &N, &M, &R);//N girl , M boy
66         for (int i = 0; i< N; i++) par[i] = i;
67         for (int i = N; i < N+M; i++) par[i] = i;//i < N是girl i >= N 是Boy
68         num = 0;
69         for (int i = 0; i < R; i++)
70         {
71             int from, to, cost;
72             scanf("%d%d%d", &from, &to, &cost);
73             to += N;
74             edge[num++] = Edge(from, to, cost);
75             edge[num++] = Edge(to, from, cost);
76         }
77         int ans = 10000*(N+M);
78         ans -= Kruskal();
79         cout << ans << endl;
80     }
81     return 0;
82 
83 }
原文地址:https://www.cnblogs.com/oscar-cnblogs/p/6403894.html