概述
Problem A:
https://blog.csdn.net/qq_41593380/article/details/81146850 很直观的解释
搬运来的HDOJ1232的ac代码,城市联通问题。比较具有普适性
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int pre[1010]; //里面全是掌门
int unionsearch(int root)
{
int son, tmp;
son = root;
while(root != pre[root]) //寻找掌门ing……
root = pre[root];
while(son != root) //路径压缩
{
tmp = pre[son];
pre[son] = root;
son = tmp;
}
return root; //掌门驾到~
}
int main()
{
int num, road, total, i, start, end, root1, root2;
while(scanf("%d%d", &num, &road) && num)
{
total = num - 1; //共num-1个门派
for(i = 1; i <= num; ++i) //每条路都是掌门
pre[i] = i;
while(road--)
{
scanf("%d%d", &start, &end); //他俩要结拜
root1 = unionsearch(start);
root2 = unionsearch(end);
if(root1 != root2) //掌门不同?踢馆!~
{
pre[root1] = root2;
total--; //门派少一个,敌人(要建的路)就少一个
}
}
printf("%dn", total);//天下局势:还剩几个门派
}
return 0;
}
Problem B:
再来一道典型例题:D. Swaps in Permutation
https://blog.csdn.net/u011481752/article/details/52017402
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;
priority_queue<int> ans[maxn];
int pre[maxn];
int n,m;
int a[maxn];
int Find(int x)
{
if(x==pre[x])
return pre[x];
return pre[x]=Find(pre[x]);
}
void join(int x,int y)
{
int fx=Find(x);
int fy=Find(y);
if(fx!=fy)
{
pre[fx]=fy;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pre[i]=i;
}
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
join(a,b);
}
for(int i=1;i<=n;i++)
{
ans[pre[Find(i)]].push(a[i]);
}
for(int i=1;i<=n;i++)
{
printf("%d ",ans[pre[Find(i)]].top());
ans[pre[Find(i)]].pop();
}
return 0;
}
和上一道题用的框架很相似,但是这个采用了优先队列来排列,值得学习
Problem C: Destroying Array
https://blog.csdn.net/mengxiang000000/article/details/52724114
ps:说实话我一开始没有想到利用并查集来做,就单纯的直接模拟硬刚,however,TLE了,也不奇怪,因为数据范围给的很大,所以暴力跑的话很容易爆time。我最后看了题解之后才恍然大悟!不得不夸张玄学高深莫测,拍案惊奇叫绝!
大概思路就是:反向逆序(离线思维)。一开始定义ans,从最后往前判断,从位置入手,倘若这一步与上一步有相邻的话,可以把它并成一起,然后searchunion的值相加,依次进行,如果没在一起的话就不用并成一类,只要比较最大值就行,因为是反向入手,最大值啥的好理解吧!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 1000005
ll pre[maxn];
ll ji[maxn];
ll vis[maxn];
ll b[maxn];
ll output[maxn];
ll unionsearch(long long root){
ll son,tmp;
son=root;
while(root!=pre[root]){
root=pre[root];
}
while(son!=root){
tmp=pre[son];
pre[son]=root;
son=tmp;
}
return root;
}
//找根结点
void merge(ll a,ll b){
ll root1,root2;
root1=unionsearch(a);
root2=unionsearch(b);
if(root1!=root2){
pre[root2]=root1;
ji[root1]+=ji[root2];//这里注意细节root1和root2
}
}
//2者归并成一体
int main()
{
ll n;
while(cin>>n){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
pre[i]=i;
cin>>ji[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
ll ans=0;
ll cnt=0;
for(int i=n;i>=1;i--){
output[cnt++]=ans;
vis[b[i]]=1;
if(b[i]-1>=1&&vis[b[i]-1]==1)
{
merge(b[i],b[i]-1);
}//判断左边
if(b[i]+1<=n&&vis[b[i]+1]==1)
{
merge(b[i],b[i]+1);
}//判断右边
ans=max(ji[unionsearch(b[i])],ans);//比较最大是否变化。
}
for(int i=cnt-1;i>=0;i--){
cout<<output[i]<<endl;
}
}
return 0;
}
最后
以上就是潇洒滑板为你收集整理的#并查集算法的全部内容,希望文章能够帮你解决#并查集算法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复