第八届蓝桥杯 并查集的使用

X星系的的防卫体系包含 n 个空间站。这 n 个空间站间有 m 条通信链路,构成通信网。
两个空间站间可能直接通信,也可能通过其它空间站中转。

对于两个站点x和y (x != y), 如果能找到一个站点z,使得:
当z被破坏后,x和y无法通信,则称z为关于x,y的关键站点。

显然,对于给定的两个站点,关于它们的关键点的个数越多,通信风险越大。

你的任务是:已知网络结构,求两站点之间的通信风险度,即:它们之间的关键点的个数。

输入数据第一行包含2个整数n(2 <= n <= 1000), m(0 <= m <= 2000),分别代表站点数,链路数。
空间站的编号从1到n。通信链路用其两端的站点编号表示。
接下来m行,每行两个整数 u,v (1 <= u, v <= n; u != v)代表一条链路。
最后1行,两个数u,v,代表被询问通信风险度的两个站点。

输出:一个整数,如果询问的两点不连通则输出-1.

例如:
用户输入:
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
应该输出:
2

这个题目核心在于 需要枚举出非起点和终点的点去掉连接的边在判断两个点是否存在连通性
检测图的连通性我们这里用的并查集这种数据结构

#include<iostream>
#include<stdio.h>
using namespace std;

int find(int pre[],int x){  //查询某个节点的树根节点 

	while(pre[x]>0){
		x=pre[x];
	}
	return x;
}

int unio(int pre[],int x,int y){  //合并2个集合 
	int a=find(pre,x);
	int b=find(pre,y);
	if(a!=b){
	
		if(pre[a]>=pre[b]){     //按高度进行路径压缩 
			if(pre[a]==pre[b])
				pre[b]--;
				pre[a]=b;	
		}
		else{
			pre[b]=a;
		}
	
	}
	
	
	
}


int  initPre(int pre[],int size){
	for(int i=0;i<size;i++)
 		pre[i]=-1;
	
} 



int main(){
	
	FILE *file=fopen("E:\\新建文本文档.txt","r");
	int n;//边数 
	int m; //顶点数  下标从1-m 
 	fscanf(file,"%d%d",&n,&m);  //为了方便 从文件读取边数和点数 
 	n--;            //最后一条是读取起点和终点 
 
	 
	int **map=new int*[n];  //初始化二维数组保存边 
	 
	int count=0;
 	while(count<n){    //文件里面读取边的消息 
	 	int x;
	 	int y;
	 	map[count]=new int[2];
	 	fscanf(file,"%d%d",&x,&y);
	 	map[count][0]=x;
	 	map[count][1]=y;
	 	count++;
 	}
 	
 	
 	int start;
 	int end;
 	fscanf(file,"%d%d",&start,&end);  //读取起点和终点消息 
 	
		int* pre=new int[m+1];     //声明一个数组 
		initPre(pre,m+1);        //初始大小为m+1数组 

 			
 			
 			//把所有边添加到集合里面检查起点和终点的连通性 
 		for(int i=0;i<n;i++){       
 			unio(pre,map[i][0], map[i][1]); 	
		}
		
 		if(pre[start]!=pre[end])  //不连通直接打印-1 
		{
			cout<<"-1";
		 	return 0;
		}	 


	int   count1=0;
 
 	//枚举去点非起点和终点的点 对于删除边 
	for(int current=1;current<=m;current++){
 		if(current==start||current==end)
 		continue;
 			
 	
 	
 		initPre(pre,m+1);//重新初始化数组 
 		for(int i=0;i<n;i++){    //删调点连接的边重新构成并查集 
 			if(map[i][0]==current||map[i][1]==current)
 			continue;
 			unio(pre,map[i][0], map[i][1]); 	
	 	}
	 	if(find(pre,start)!=find(pre,end))//检查起点和终点是否连通 
	 		count1++;

		
 		
 		
	 }
	 
	 cout<<count1;
	 
	 
	 delete []pre;
	 delete []map;


 		
	
} 

猜你喜欢

转载自blog.csdn.net/qq_40066334/article/details/86371627