并查集_Hdu1232(畅通工程)

并查集

在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。

主要操作

  • 初始化:把每个点所在集合初始化为其自身。通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(N)。
  • 查找:查找元素所在的集合,即根节点。
  • 合并:将两个元素所在的集合合并为一个集合。通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。

例题

Hdu1232(畅通工程)

首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。n个连通分支,就是n-1条路。

//畅通工程 
#include <bits/stdc++.h>
using namespace std;
const int maxn=1010;
int fa[maxn];
int sum; 
int find(int x){//找祖先 
    if(x == fa[x]){
        return x;
    }
    else{
        fa[x] = find(fa[x]);
        return fa[x];
    }
}
 
void unit(int x, int y){//不同祖先就把他们连通 
    int fx = find(x);
    int fy = find(y);
    if (fx == fy){
        return;
    }
    fa[fx] = fy;
}
 
bool same(int x, int y){//判断是否同祖先 
    if (find(x) == find(y)){
        return true;
    }
    return false;
}

int main() 
{
	std::ios::sync_with_stdio(false);	
	int n,m,i,x,y,root1,root2;
	while(cin>>n>>m&&n){
		for(int i=1;i<=n;i++) fa[i]=i;
		int sum=n-1;//初始有n-1条路 
		while(m--) {
			cin>>x>>y;
			if(!same(x,y)){//若不同祖先 ,即不连通 
				unit(x,y);//就把他们连通 
				sum--;//需要的路就少一条 
			}
			/*root1=find(x);
			root2=find(y);
			if(root1!=root2)//若不同祖先 ,即不连通 
			{
				fa[root1]=root2;//就把他们连通 
				sum--; //需要的路就少一条 
			}*/	
		}
		cout<<sum<<endl;
	}		
}

猜你喜欢

转载自blog.csdn.net/aaakkk_1996/article/details/81781120