专栏文章
题解:P5036 随机生成树
P5036题解参与者 3已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @miogp4pf
- 此快照首次捕获于
- 2025/12/02 18:55 3 个月前
- 此快照最后确认于
- 2025/12/02 18:55 3 个月前
P5036 随机生成树
题意概括
其实就是满足要求的连通块数量最大值。
思路
可以很快地想到 Kruskal 算法,但这题的难点不在这。
难点在于其要求的排序方式:
- 对连通块有贡献的优先。
- 满足条件一时,编号之和最小的优先。
- 同时满足条件二时,连接的两个点编号的之中较小的一个较小的边优先。
这里的排序条件 应该是:
CPPbool cmp(edge a,edge b){
if (a.w==b.w){
if (a.u+a.v==b.u+b.v){
return min(a.u,a.v)<min(b.u,b.v);
}
return a.u+a.v<b.u+b.v;
}
return a.w>b.w;
}
还有一个需要考虑的是如何判断贡献:
如果一条边的两端点的颜色 和 是相同的,显而易见的,连通块的数量会少,也就是其对生成连通块没有贡献。
代码
最后是代码,其他的注释都在里面了:
CPP#include <bits/stdc++.h>
using namespace std;
const int N=500005;
int n,c[N],f[N],cnt; //声明变量
struct edge{
int u,v,w; //边要开多一点
}e[10000005];
int find(int x){
if (x==f[x]) return x;
else return f[x]=find(f[x]); //经典并查集
}
bool cmp(edge a,edge b){ //排序规则
if (a.w==b.w){
if (a.u+a.v==b.u+b.v){
return min(a.u,a.v)<min(b.u,b.v);
}
return a.u+a.v<b.u+b.v;
}
return a.w>b.w;
}
void kruskal(){
for (int i=1;i<=cnt;i++){
int fa1=find(e[i].u);
int fa2=find(e[i].v);
if (fa1==fa2) continue;
f[fa1]=fa2;
cout << e[i].u << " " << e[i].v << endl; //Kruskal
}
}
int main(){
cin >> n;
for (int i=1;i<=n;i++) cin >> c[i]; //读入
for (int i=1;i<=n;i++) f[i]=i; //初始化
for (int i=1;i<=n;i++){
for (int j=i*2;j<=n;j+=i){ //这里可以满足题里必须要连自身约数倍数
e[++cnt].u=i;
e[cnt].v=j;
if (c[i]==c[j]) e[cnt].w=-114514;
else e[cnt].w=1919810;
} //只要能分辨就行,数字不重要
}
sort(e+1,e+1+cnt,cmp); //排序
kruskal();
return 0;
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...