专栏文章
题解:AT_jsc2019_qual_e Card Collector
AT_jsc2019_qual_e题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min036ic
- 此快照首次捕获于
- 2025/12/01 18:22 3 个月前
- 此快照最后确认于
- 2025/12/01 18:22 3 个月前
Sol
首先这类网格问题考虑经典地转化为二分图。具体地,左侧点代表各行,右侧点代表各列,把存在的点转化为连接其行列代表点的一条边。
考虑现在变成了一个什么问题,每个点都可以选一条临边并得到边权,每条边只能被选一次。那么选出来之后必然形如基环树森林,同时任一生成基环树森林也都可以找到相应方案。故而直接贪心地找最大权基环树森林即可,类似于 Kruskal 算法,按边权降序能加边就加边,容易反证法证明正确性。
Code
CPPint n,r,c;
struct edge{int a,b;ll c;}es[N];
ll sum;
bool use[N],don[N];
int fa[N];
int find(int x){if(fa[x]!=x)fa[x]=find(fa[x]);return fa[x];}
void merge(int a,int b){a=find(a),b=find(b),fa[a]=b,don[b]|=don[a];}
bool same(int a,int b){return find(a)==find(b);}
inline void Main(){
cin>>n>>r>>c;
rep(i,1,n){
cin>>es[i].a>>es[i].b>>es[i].c;
es[i].b+=r;
}
rep(i,1,r+c)fa[i]=i;
sort(es+1,es+1+n,[&](edge a,edge b){return a.c>b.c;});
rep(i,1,n)if(!same(es[i].a,es[i].b)&&(!don[find(es[i].a)]||!don[find(es[i].b)])){
use[i]=1;
merge(es[i].a,es[i].b);
sum+=es[i].c;
}else if(same(es[i].a,es[i].b)&&!don[find(es[i].a)]){
don[find(es[i].a)]=1;
sum+=es[i].c;
}
put(sum);
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...