CF875F Royal Questions 基环树、Kruskal

题目传送门:http://codeforces.com/problemset/problem/875/F

题意:有$N$个王子和$M$个公主,每个公主或王子都只能选择至多一个王子或公主作为自己的结婚对象(王子选择公主,公主选择王子不然还怎么选)。每个公主有且仅有两个中意的王子$a,b$,她只会至多选择其中一个作为自己的结婚对象,而如果某个公主选择了自己的结婚对象,就会给出$w$的嫁妆。求在满足所有公主的条件的情况下能够给出的最大嫁妆。$N,M \leq 2 \times 10^5 , w \leq 10^4$


很像带权二分图最大匹配,然而用KM或者费用流复杂度难以保证,考虑使用其他算法。

我们将王子作为点,某一个公主对应的两个王子之间连一条边,边权为公主的嫁妆,那么我们的题目变成了:选择若干条边,使得每条边只匹配其中一个端点(某个公主选择其中一个王子)的情况下不匹配重复的端点(王子选择一个公主),而且边权最大。于是本题与棋盘上的守卫变为相同的模型。

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define MAXN 200010
 4 using namespace std;
 5 
 6 struct Edge{
 7     int start , end , w;
 8 }Ed[MAXN];
 9 int A , B , fa[MAXN];
10 bool vis[MAXN];
11 
12 bool operator <(Edge a , Edge b){
13     return a.w > b.w;
14 }
15 
16 int find(int x){
17     return fa[x] == x ? x : (fa[x] = find(fa[x]));
18 }
19 
20 int main(){
21     ios::sync_with_stdio(0);
22     cin.tie(0);
23     cout.tie(0);
24     int A , B , ans = 0;
25     cin >> A >> B;
26     for(int i = 1 ; i <= B ; i++)
27         cin >> Ed[i].start >> Ed[i].end >> Ed[i].w;
28     for(int i = 1 ; i <= A ; i++)
29         fa[i] = i;
30     sort(Ed + 1 , Ed + B + 1);
31     for(int i = 1 ; i <= B ; i++){
32         int p = find(Ed[i].start) , q = find(Ed[i].end);
33         if(p == q){
34             if(!vis[p]){
35                 vis[p] = 1;
36                 ans += Ed[i].w;
37             }
38         }
39         else
40             if(!(vis[p] && vis[q])){
41                 fa[q] = p;
42                 vis[p] |= vis[q];
43                 ans += Ed[i].w;
44             }
45     }
46     cout << ans;
47     return 0;
48 }

猜你喜欢

转载自www.cnblogs.com/Itst/p/9774571.html