poj - 3723 Conscription(最大权森林)

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

windy需要挑选N各女孩,和M各男孩作为士兵,但是雇佣每个人都需要支付10000元的费用,如果男孩x和女孩y存在亲密度为d的关系,只要他们其中有一个已经被选中,那么在选另一个人需要的费用为100000-d,给定R个关系,输出一个最低费用,每个关系只能使用一次。

把人看作顶点,关系看作边,就可以转化为无向图中的最大权森林问题,最大权森林问题可以通过把所有边权取反之后用最小生成树的算法求解。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int maxn =20010;
 6 struct edge {
 7     int u,v,cost;
 8     edge() {}
 9     edge(int a,int b,int c) {
10         u=a;
11         v=b;
12         cost=c;
13     }
14 };
15 bool cmp(const edge& e1,const edge& e2)
16 {
17     return e1.cost<e2.cost;
18 }
19 
20 edge es[50010];
21 int par[maxn];
22 int N,M,R;
23 
24 void init(int n) {
25     for(int i=0;i<n;i++) par[i]=i;
26 }
27 
28 int find(int x) {
29     return x==par[x]?x:par[x]=find(par[x]);
30 }
31 
32 void unite(int x,int y) {
33     x=find(x);
34     y=find(y);
35     if(x!=y) par[x]=y;
36 }
37 
38 int kruskal() {
39     sort(es,es+R,cmp);
40     init(N+M);
41     int res=0;
42     for(int i=0;i<R;i++) {
43         edge e=es[i];
44         if(find(e.u)!=find(e.v)) {
45             unite(e.u,e.v);
46             res+=e.cost;
47         }
48     }
49     return res;
50 }
51 
52 int main() {
53    // freopen("a.txt","r",stdin);
54     int t;
55     scanf("%d",&t);
56     while(t--)
57     {
58         int x,y,d;
59         scanf("%d%d%d",&N,&M,&R);
60         for(int i=0;i<R;i++)
61         {
62             scanf("%d%d%d",&x,&y,&d);
63             es[i]=(edge){x,y+N,-d};
64             //printf("%d %d %d\n",es[i].u,es[i].v,es[i].cost);
65         }
66         printf("%d\n",10000*(N+M)+kruskal());
67     }
68     return 0;
69 }

 

posted @ 2015-05-17 20:41  NowAndForever  阅读(512)  评论(0编辑  收藏  举报