【最大权森林/Kruskal】POJ3723-Conscription

【题目大意】

招募m+n个人每人需要花费$10000,给出一些关系,征募某个人的费用是原价-已招募人中和他亲密值的最大值,求最小费用。

【思路】

人与人之间的亲密值越大,花费越少,即求出最大权森林,可以用最小(大)生成树的思路来解决。按亲密值由大到小排序,对于每一个关系,判断两人是否在一个集合中,在则跳过,否则从总钱数中减去亲密值,合并两个集合。注意:人的编号是从0开始的!

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int MAXN=100000+5;
 6 struct Rec
 7 {
 8     int ori,des,len;
 9     bool operator < (const Rec &x) const
10     {
11         return len>x.len;
12     }
13 }edge[MAXN*5];
14 int par[MAXN*2],height[MAXN*2];
15 int n,m,r;
16 /*n代表女兵,m代表男兵,这里不需要用到二分图;r代表关系数*/
17 int ans;
18 
19 void initset()
20 {
21     for (int i=0;i<(n+m);i++)
22     {
23         par[i]=i;
24         height[i]=0;
25     }
26 }
27 
28 int find(int x)
29 {
30     int r=x,temp;
31     while (par[r]!=r) r=par[r];
32     while (x!=r)
33     {
34         temp=par[x];
35         par[x]=r;
36         x=temp;
37     }
38     return (r);
39 }
40 
41 void unionset(int fa,int fb)
42 {
43     if (height[fa]>=height[fb])
44     {
45         par[fb]=fa;
46         if (height[fa]==height[fb]) height[fa]++;
47     }
48     else 
49         par[fa]=fb;
50 }
51 
52 int main()
53 {
54     int kase;
55     scanf("%d",&kase);
56     for (int cases=0;cases<kase;cases++)
57     {
58         scanf("%d%d%d",&n,&m,&r);
59         int ans=10000*(m+n);
60         for (int i=0;i<r;i++)
61         {
62             int u,v,w;
63             scanf("%d%d%d",&u,&v,&w);
64             edge[i].ori=u;
65             edge[i].des=v+n;
66             edge[i].len=w;
67         }
68         sort(edge,edge+r);
69         initset();
70         for (int i=0;i<r;i++)
71         {
72             int fa=find(edge[i].ori);
73             int fb=find(edge[i].des);
74             if (fa!=fb)
75             {
76                 unionset(fa,fb);
77                 ans-=edge[i].len;
78             }
79         }
80         cout<<ans<<endl;
81     }
82     system("pause");
83     return 0;
84 }

 

posted @ 2015-08-06 15:30  iiyiyi  阅读(410)  评论(0编辑  收藏  举报