洛谷AT_jsc2019_qual_e Card Collector 题解

发布时间 2023-07-24 11:42:31作者: Idtwtei

题目链接

Card Collector - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

将每一行、每一列转化为点,第i行第j列的卡牌转化为i->j+m(m为行数)的有向边。

总共会抽取m+n(m为行数,n为列数)张牌,每个点的出度为1。结果图为基环森林;

那么题目就转化为求最大基环森林。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=100005;
 5 
 6 struct EDGE{
 7     int x,y,w;
 8 }edge[N];
 9 bool cmp(EDGE a, EDGE b){
10     return a.w>b.w;
11 }
12 
13 bool f[N*2];//每个联通块是否有环
14 int fa[N*2];
15 int find(int x){
16     if(fa[x]==x) return x;
17     return fa[x]=find(fa[x]);
18 }
19 
20 int main(){
21     int e,m,n;
22     scanf("%d %d %d", &e, &m, &n);
23     for(int i=1;i<=e;i++){
24         scanf("%d %d %d", &edge[i].x, &edge[i].y, &edge[i].w);
25         edge[i].y+=m;
26     }
27     sort(edge+1,edge+e+1,cmp);
28     for(int i=1;i<=n+m;i++) fa[i]=i;
29     long long ans=0;//需要开long long
30     for(int i=1;i<=e;i++){
31         int x=edge[i].x,y=edge[i].y,w=edge[i].w;
32         int p=find(x),q=find(y);
33         if(p==q&&!f[p]) ans+=w,f[p]=1;
34         else if(p!=q&&!(f[p]&f[q])){//不在同一连通块&&两个连通块不是都有环
35             f[q]=f[q]|f[p];//更新是否有环
36             fa[p]=q;
37             ans+=w;
38         }
39     }
40     cout<<ans;
41     return 0;
42 }