Poj 3723 Conscription

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

题意:需要招募女兵N人,男兵M人。每征募一人需要$10000。但是如果两个人之间(已征募与要被征募)有关系,就可以依据亲密度大小减免花费,此时花费等于10000-已经征募的人中与ta的最大亲密度。求花费最少的招募顺序。

题解:是一个无向图,并且可以得知这是一个森林,所以可以把人看做点,关系是边权,就转换为求最大权森林。将边权取反,采用kruskal(因为可能有圈)。

  1 //
  2 //  main.cpp
  3 //  poj 3723
  4 //
  5 //  Created by zhang on 14-3-31.
  6 //  Copyright (c) 2014年 apple. All rights reserved.
  7 //
  8 
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <cmath>
 12 #include <algorithm>
 13 #include <queue>
 14 #include <stack>
 15 #include <cstdlib>
 16 
 17 using namespace std;
 18 
 19 const int maxn=50010;
 20 
 21 int par[maxn];//并查集父亲
 22 int hrank[maxn];//并查集树的高度
 23 int x[maxn],y[maxn],d[maxn];
 24 struct edge{
 25     int u,v,cost;
 26 };
 27 edge es[maxn];
 28 int V,E;
 29 void init(int n)
 30 {
 31     for (int i=0; i<n; i++) {
 32         par[i]=i;
 33         hrank[i]=0;
 34     }
 35 }
 36 
 37 int find(int x)
 38 {
 39     if (par[x]==x) {
 40         return x;
 41     }
 42     else {
 43         return par[x]=find(par[x]);
 44     }
 45 }
 46 
 47 void unite(int x,int y)
 48 {
 49     x=find(x);
 50     y=find(y);
 51     if (x==y) {
 52         return;
 53     }
 54     if (hrank[x]<hrank[y]) {
 55         par[x]=y;
 56     }
 57     else {
 58         par[y]=x;
 59         if (hrank[x]==hrank[y]) {
 60             hrank[x]++;
 61         }
 62     }
 63 }
 64 
 65 bool same(int x,int y)
 66 {
 67     return find(x)==find(y);
 68 }
 69 
 70 bool cmp(const edge& e1,const edge& e2)
 71 {
 72     return e1.cost<e2.cost;
 73 }
 74 
 75 int kruskal()
 76 {
 77     sort(es, es+E, cmp);
 78     init(V);
 79     int res=0;
 80     for (int i=0; i<E; i++) {
 81         edge e=es[i];
 82         if (!same(e.u,e.v)) {
 83             unite(e.u, e.v);
 84             res+=e.cost;
 85         }
 86     }
 87     return res;
 88 }
 89 
 90 int main()
 91 {
 92     //freopen("/Users/apple/Desktop/poj 3723/poj 3723/in", "r", stdin);
 93     //freopen("/Users/apple/Desktop/poj 3723/poj 3723/out", "w", stdout);
 94     int n;
 95     int N,M,R;
 96     scanf("%d",&n);
 97     for (int i=0; i<n; i++) {
 98         scanf("%d%d%d",&N,&M,&R);
 99         V=N+M;
100         E=R;
101         for (int j=0; j<R; j++) {
102             scanf("%d%d%d",&x[j],&y[j],&d[j]);
103             es[j]=(edge){x[j],N+y[j],-d[j]};//N+y[j]……
104         }
105         printf("%d
",10000*(N+M)+kruskal());
106         
107     }
108     
109     return 0;
110 }
原文地址:https://www.cnblogs.com/der-z/p/3636755.html