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\n",10000*(N+M)+kruskal()); 106 107 } 108 109 return 0; 110 }