【最大权森林/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 }