[Algorithm notes] and check the set

This article is reproduced from: http://www.javaxxz.com/thread-359245-1-1.html

The teacher didn't talk about this thing in class, but it sounded very high. When I saw the topic and said to use it and found it, ψ(..) What! ? And check the set? What the hell? Forget it, let go of this question and brush up on something else. Today I researched and checked the collection, and found that it is quite simple. I will organize it on the blog, and I forgot to take a look at it later _(¦3"∠)_

and check

The union check set is mainly used to detect whether two points are connected. There are two main functions, one is find and the other is join. As for when to use union search, I think you think you need to judge whether these two points are connected. For example, if there are several roads between several cities, judge whether two cities are connected.

①Initialization of the union search set

    The union search set is generally stored in a one-dimensional array, where pre[i]=i indicates that it is connected to itself, that is to say, no path has been added between the points.

 

② and check the set join

    Join is mainly used to add a path to the one-dimensional array that stores and searches the set. First, determine whether the two points are connected. If they are connected, there is no need to add a path. If they are not connected, connect the root nodes of the two points together. .

void join(int x,int y){
	int i,j;
	i = find(x); //find the root node of x
	j = find(y); //find the root node of y
	if(i!=j) //If the two root nodes are different, that is, they are not connected, connect the root nodes together
		pre[i] = j; //i.e. i link j
}

③ And check the set find

    find mainly has two parts, one is to find the root node, and the other is to compress the path.

int find(int x){	int i = x;	while(pre[i]!=i)  //查找根节点 		i = pre[i];	//路径压缩	int j = x;	int k;	while(j!=i)   	{		k = pre[j];		pre[j] = i;		j = k;	}	return i;}

There are two examples below to explain in detail the usage of concatenating sets

Risk measurement of previous exam questions of the Blue Bridge Cup

The defense system of galaxy X consists of n space stations. There are m communication links between the n space stations, forming a communication network.
There may be direct communication between the two space stations, or transit through other space stations.
For two sites x and y (x != y), if a site z can be found such that
when z is destroyed, x and y cannot communicate, then z is called a key site about x, y.
Obviously, for a given two sites, the greater the number of keypoints about them, the greater the communication risk.
Your task is: Knowing the network structure, find the communication risk between two sites, that is: the number of key points between them.

The first line of the input data contains 2 integers n (2 <= n <= 1000), m (0 <= m <= 2000), which represent the number of stations and the number of links, respectively.
Space stations are numbered from 1 to n. A communication link is represented by the station numbers at both ends of it.
The next m lines, each line with two integers u, v (1 <= u, v <= n; u != v) represent a link.
The last line, two numbers u, v, represent the two sites being asked about the risk of communication.

Output: an integer, if the two points asked are not connected, output -1.

For example:
user input:
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
, the program should output:
2

#include<iostream>using namespace std;int pre[1001];int u[2001],v[2001];int find(int x){	int i = x;	while(pre[i]!=i)  //查找根节点 		i = pre[i];	//路径压缩	int j = x;	int k;	while(j!=i)   	{		k = pre[j];		pre[j] = i;		j = k;	}	return i;}void join(int x,int y){	int i,j;	i = find(x);	j = find(y);	if(i!=j)		pre[i] = j;}int main(){	int n,m;	cin>>n>>m;	int i,x,y;	for(i=0;i<n;i++) 		pre[i] = i;	for(i=0;i<m;i++)	{		cin>>x>>y;		u[i] = x;		v[i] = y;		join(x,y);	}	cin>>x>>y;	if(find(x)!=find(y))  //如果不连通就输出-1		cout<<"-1"<<endl;	else  //如果连通,寻找有几个关键站点	{		int res = 0;		for(i=0;i<n;i++)  //因为数据很小,所以暴力枚举,从第一个站点开始判断是否是关键站点  		{			if(i==x||i==y)   //如果i是x和y这两个需要判断是否连通的站点的其中一个就跳过 				continue;			for(int k=0;k<n;k++)  //初始化pre数组 				pre[k] = k;			for(int j=0;j<m;j++)  //按照输入顺序jion			{				if(u[j]==i||v[j]==i)  //如果是i这个站点,就不在pre里面加链接这个站点的路径					continue;				join(u[j],v[j]);			}			if(find(x)!=find(y))  //如果x和y不连通了,说明站点i是关键站点 				res++;		}		cout<<res<<endl;	}	return 0;}

 

2005年浙江大学计算机复试  通畅工程  NYOJ608

 

畅通工程

时间限制: 2000 ms  |  内存限制: 65535 KB
难度: 3
描述
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路? 
输入
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。
输出
对每个测试用例,在1行里输出最少还需要建设的道路数目。
样例输入
4 21 34 33 31 21 32 35 21 23 5999 00
样例输出
102998

这个题好烦,WA了好多次最后发现是一个小小小错误,还有说我超时,把cin全部换成scanf什么的了。还有一种写法比这个感觉稍微麻烦一点点,可以了解一下。

方法一:n个站点最多有n-1个条路径使所有站点相连即total=n-1,如果一个站点i的pre[i]不等于自己本身,也就是这个站点处于一段连通的路径里面一个,所以total可以减1,判断完所有站点之后total为还需要修路的站点。

方法二:要将n个站点相连通,也就是要将每个连通路径的根节点相连通,求出根节点的数量num,最终还需要修建的路径数就为num-1。

#include<iostream>#include<stdio.h>using namespace std;int pre[1005];int find(int x){	int i = x;	while(pre[i]!=i) 		i = pre[i];	return i;}int main(){	int n,m;	int i,a,b,total,fa,fb;	while(scanf("%d",&n) && n!=0)	{		scanf("%d",&m);		total = n-1;  //n个站点全部连通最少需要n-1条路径		for(i=1;i<=n;i++)			pre[i] = i;		for(i=1;i<=m;i++)		{			scanf("%d%d",&a,&b);			fa = find(a);			fb = find(b);			if(fa!=fb)				pre[fa] = fb;		}		for(i=1;i<=n;i++)		{			if(pre[i]!=i)  //也就是有相连的路径				total --;		}		printf("%d\n",total);	}	return 0;}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326088858&siteId=291194637