zoukankan      html  css  js  c++  java
  • 带权并查集初步

    简单学习了一下带权并查集,参考了这个博客,感觉写的不错:https://blog.csdn.net/yjr3426619/article/details/82315133

    和一般的并查集相比,代码的变化主要在路径压缩和合并的时候。因为带上了权值,所以路径压缩的时候要更新权值(一般v[x]表示的都是x与par[x]之间的权值,需要更新成x与x的根之间的权值)。然后合并的时候,找到x和y的根px和py,将px连接向py(或py连向px)的时候,也要算出两者的权值。具体的更新代码和图看上面的博客就好,讲的挺清楚。

    下面记录三道题目吧,自己实现了博客里的例题。

    hdu 3038:题目链接:https://vjudge.net/problem/HDU-3038

    大意就是给你一系列区间和,判断有多少个和之前给定的矛盾(如果是矛盾就跳过)。可以用带权并查集来做:把结点看做区间的端点,两个结点之间的权值看做这个区间内的和。当前给定的两个结点属于同一个集合时,可以求出它们的区间和,然后判断是否和给定的值相等,如果不相等则ans++;若不属于同一个集合,就把它们对应的根合并,并求出两个根之间的权值。基本是模板题,但有一个点要注意:每次读入的时候要把左边端点当做开区间(使得左边端点-1即可)。举例:比如区间[1,4],读入了[1,2]和[1,4]后就可以确定[3,4],但是实际执行的时候会把3,4当做在不同的集合。但是改成(0,2]和(2,4]就不会有这个问题了,此时读入[3,4]相当于求(2,4],2和4属于同一个集合。

    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    const int maxn=200+10;
    int par[maxn],v[maxn];
    int n,m,xx,x,y,t,i,j;
    
    int find(int x){ //带权路径压缩 
    	if (par[x]==x) return x;
    	else{
    		int p=par[x];
    		par[x]=find(par[x]);
    		v[x]+=v[p];
    		return par[x];
    	}
    }
    
    int main(){
    	//freopen("hdu3038.txt","r",stdin);
    	while (~scanf("%d%d",&n,&m)){
    		int ans=0;
    		for (i=0;i<=n;i++) par[i]=i;
    		memset(v,0,sizeof(v));
    		for (i=1;i<=m;i++){
    			scanf("%d%d%d",&xx,&y,&t);
    			x=xx-1; //
    			int px=find(x);int py=find(y);
    			if (px==py){
    				int d=v[x]-v[y];  //***
    				if (d!=t) ans++;
    			} 
    			else{
    				par[px]=py;
    				v[px]=v[y]-v[x]+t; //***
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	//fclose(stdin);
    	return 0;
    }
    

    hihocoder1515

    题目链接:https://vjudge.net/problem/HihoCoder-1515

    水题,设v[x]表示x比x当前的父亲par[x]低多少分就行了(我觉得设低多少分舒服一些......

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=100+10;
    int par[maxn],v[maxn]; //v[x]表示x比par[x]低多少分 
    int s,n,m,q,t,i,j,x,y;
    
    int find(int x){
    	if (par[x]==x) return x;
    	else{
    		int p=par[x];
    		par[x]=find(par[x]);
    		v[x]+=v[p];
    		return par[x]; 
    	}
    }
    
    int main(){
    	//freopen("hiho1515.txt","r",stdin);
    	scanf("%d%d%d",&n,&m,&q);
    	for (i=1;i<=n;i++) par[i]=i;
    	memset(v,0,sizeof(v));
    	for (i=1;i<=m;i++){
    		scanf("%d%d%d",&x,&y,&s);s=-s;
    		int px=find(x);int py=find(y);
    		if (px!=py){
    			par[px]=py;
    			v[px]=v[y]-v[x]+s;
    		}
    	}
    	for (i=1;i<=q;i++){
    		scanf("%d%d",&x,&y);
    		int px=find(x);int py=find(y);
    		if (px!=py) printf("-1
    ");else printf("%d
    ",v[y]-v[x]);
    	}
    	//fclose(stdin);
    	return 0;
    }
    

      

    poj1182 食物链

    题目链接:https://vjudge.net/problem/POJ-1182

    这题应该算是经典题了,同时也有点变化。自己脑补了一会成功弄出来了(主要是看到了博客里一个模3的提示......)

    设v[x]=0表示x和par[x]是同类,v[x]=1表示x吃par[x],v[x]=2表示x被par[x]吃。更新的时候代码要做相应的变化。一是路径压缩的时候v[x]=(v[x]+v[p])%3,二是求x和y的权值t,t=(v[x]-v[y]+3)%3,三是合并px和py,求px和py之间的权值的时候,v[px]=(v[y]-v[x]+t+3)%3。

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=500+10;
    int par[maxn],v[maxn];  
    int t,i,j,k,n,m,d,x,y,ans;
    
    int find(int x){
    	if (par[x]==x) return x;
    	else{
    		int p=par[x];
    		par[x]=find(par[x]);
    		v[x]=(v[p]+v[x])%3;  //* 
    		return par[x];
    	}
    }
    
    int main(){
    	//freopen("poj1182.txt","r",stdin);
    	scanf("%d%d",&n,&k);
    	for (i=1;i<=n;i++) par[i]=i;
    	memset(v,0,sizeof(v));
    	ans=0;
    	for (i=1;i<=k;i++){
    		scanf("%d%d%d",&d,&x,&y);
    		if (x<1||x>n||y<1||y>n) {
    		    ans++;continue;	
    		}
    		int px=find(x);int py=find(y);
    		if (px==py){
    			t=(v[x]-v[y]+3)%3; //*
    			if (d==1&&t!=0) ans++;
    			if (d==2&&t!=1) ans++;
    		}
    		else{
    			t=d-1; //* 
    			par[px]=py;
    			v[px]=(v[y]-v[x]+t+3)%3; //*
    		}
    	}
    	printf("%d
    ",ans);
    	//fclose(stdin);
    	return 0;
    }
    

      

  • 相关阅读:
    Win10设置文件夹权限报错-(提示:无法枚举容器中的对象 访问被拒绝)
    判断上传文件是否是图片文件
    PB调用C#编写的Dll类库
    C#txt文件创建并写入信息
    三十分钟学完Vue
    html增加锚点定位
    Asp.Net WebApi 调试利器“单元测试”
    ios端 返回上一级后 卡在正在加载中处理方式
    [转]如何为图片添加热点链接?(map + area)
    JS获取当前时间并格式化"yyyy-MM-dd HH:mm:ss"
  • 原文地址:https://www.cnblogs.com/edmunds/p/12524390.html
Copyright © 2011-2022 走看看