zoukankan      html  css  js  c++  java
  • 并查集刷题整理

    并查集刷题整理

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

    比较经典的应用就是最小生成树(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;
    }
    
  • 相关阅读:
    WCF 第四章 绑定 在多个绑定上暴露一个服务契约
    WCF 第五章 行为 事务跨操作事务流
    WCF 第五章 导出并发布元数据(服务行为)
    WCF 第五章 行为 通过配置文件暴露一个服务行为
    WCF 第五章 不支持会话的绑定的默认并发和实例
    WCF 第五章 并发和实例(服务行为)
    WCF 第五章 行为 总结
    WCF 第四章 绑定 绑定元素
    WCF 第五章 行为 事务之选择一个事务协议OleTx 或者WSAT
    WCF 第四章 绑定 比较各种绑定的性能和可扩展性
  • 原文地址:https://www.cnblogs.com/648-233/p/12628884.html
Copyright © 2011-2022 走看看