• 并查集刷题整理


    并查集刷题整理

    并查集是一种数据结构,然而用于维护其的数组及函数又极少,用途极为广泛,被广泛地应用于极多的综合题目,

    比较经典的应用就是最小生成树(kruskal)算法

    T1:Watering Hole G

    题意

    (n)个牧场,需要挖井,在第(i)号农场挖需要(W_i)元,在(i)(j)号之间通水需要(P_{i,j}=P_{j,i})元,问最小花费.

    思路:

    显然这并不是最短路问题,是最小生成树问题,目的就是将所有农场通过花费最小的路径进行串通

    对于"挖井"这个放在最小生成树中稍显生疏的操作,实际上通过建新点的操作,可以将挖井的初始花费转变成"地下水到井"的距离,以此将挖井的初始花费转变成边,进行(kruskal)

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=305;
    int n;
    struct Ed{
    	int from,to,dis;
    };
    bool operator<(const Ed &a,const Ed &b){
    	return a.dis<b.dis;
    }
    bool operator>(const Ed &a,const Ed &b){
    	return a.dis>b.dis;
    }
    priority_queue<Ed,vector<Ed>,greater<Ed> > q;
    int fa[N];
    inline int find(int x){
    	if(fa[x]==x) return x;
    	return fa[x]=find(fa[x]);
    }
    int main(){
    	//freopen("P1550_2.in","r",stdin);
    	scanf("%d",&n);
    	for(int i=0;i<=n;++i) fa[i]=i;
    	for(int i=1;i<=n;++i){
    		int dis;
    		scanf("%d",&dis);
    		q.push((Ed){0,i,dis});
    	}
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j){
    			int dis;
    			scanf("%d",&dis);
    			if(i!=j)
    				q.push((Ed){i,j,dis});
    		}
    	int ans=0;
    	while(!q.empty()){
    		Ed u=q.top();
    		q.pop();
    		int x=u.from,y=u.to;
    		if(find(x)==find(y)) continue;
    		ans+=u.dis;
    		fa[fa[x]]=fa[y];
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    p.s.

    本题需要注意的是在进行按边权排序的时候,最好用小根堆,不要用结构体数组+(sort)函数,因为凿井价值的加入,并不好掌握边的数量,不方便对边进行排序,容易出错

    T2:同学

    题意:

    (A)(B)两个公司,(A)公司全部是男员工,(B)全部是女员工,分别有(n),(m)个员工,,分别有(p),(q)条公司内的关系,问最多通过两公司的1号员工能够配成多少情侣

    思路:

    看上去这是二分图匹配,毕竟是求匹配方案,但是这就奇怪在两公司之间并没有关系,只是单纯通过两公司的1号进行交流,这样一来,将题意转化,就可以明确:

    其实就是要求两公司内与1号员工有直接或间接关系的员工的数目的较小值

    再次翻译:

    在两边各跑一遍并查集看哪个公司中与1号员工属同一集合的员工数较小

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=20005;
    int n,m,p,q;
    int afa[N],bfa[N];
    inline int afind(int x){
    	if(afa[x]!=x) afa[x]=afind(afa[x]);
    	return afa[x];
    }
    inline int bfind(int x){
    	if(bfa[x]!=x) bfa[x]=bfind(bfa[x]);
    	return bfa[x];
    }
    int main(){
    	scanf("%d%d%d%d",&n,&m,&p,&q);
    	for(int i=1;i<=n;++i) afa[i]=i;
    	for(int i=1;i<=m;++i) bfa[i]=i;
    	for(int i=1;i<=p;++i){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		if(afind(x)!=afind(y)) afa[afa[x]]=afa[y];
    	}
    	for(int i=1;i<=q;++i){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		x=-x;
    		y=-y;
    		if(bfind(x)!=bfind(y)) bfa[bfa[x]]=bfa[y];
    	}
    	int jostar=afind(1);
    	int dio=bfind(1);
    	int a=0,b=0;
    	for(int i=1;i<=n;++i)
    		if(afind(i)==jostar) ++a;
    	for(int i=1;i<=m;++i)
    		if(bfind(i)==dio) ++b;
    	printf("%d
    ",min(a,b));
    	return 0;
    }
    
  • 相关阅读:
    马哥教育N63013第十周作业
    马哥教育N63013第八周作业
    马哥教育N63013第十二周作业
    终于开通博客园的博客了
    Teradata 查看表的列名
    基础一 数据结构
    ubuntu 快速安装ninja和gn
    linux格式化文件命令
    ESP8266_RTOS_SDK更新子模块出错git remote: [sessionf0448081] 404 not found!
    springboot 自动配置原理
  • 原文地址:https://www.cnblogs.com/648-233/p/12628884.html
Copyright © 2020-2023  润新知