【蓝桥杯】危险系数(C++)(DFS求割集)

问题描述
抗日战争时期,冀中平原的地道战曾发挥重要作用。

地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

我们来定义一个危险系数DF(x,y):

对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点。相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数。

本题的任务是:已知网络结构,求两站点之间的危险系数。

输入格式
输入数据第一行包含2个整数n(2 <= n <= 1000), m(0 <= m <= 2000),分别代表站点数,通道数;

接下来m行,每行两个整数 u,v (1 <= u, v <= n; u != v)代表一条通道;

最后1行,两个数u,v,代表询问两点之间的危险系数DF(u, v)。

输出格式
一个整数,如果询问的两点不连通则输出-1.
样例输入
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
样例输出
2

思想:
1、很容易看出是求割点的问题,两个点之间所有的通路必定过两个点之间的割点,那么我们很容易知道,如果以一个点为起点,另一个点为终点,那么采用深搜的策略,找到所有两个点之间的通路,并且每次访问到终点时,就将通路上的所有点访问次数+1,当所有的路找到后,寻找与终点访问次数相同的中间点,那么这些点就为割点。
2、那么当我我们找到一条通路时,如何把这条通路上的所有点访问次数+1,这里我构造了记录前节点的数组pre,pre[i] = j,表示i的前一个节点为j

代码如下:

#include<iostream> 
#include<vector>

using namespace std;

int rec[1010] = {0}; //记录节点的访问次数rec[i] = 2;表示i节点被访问2次 
int vis[1010] = {0}; //记录哪些节点被访问过 
int pre[1010] = {0};

int num = 0;  

vector<int> vc[1010]; 

int st,des;

void dfs(int st){ //st为当前节点 
	vis[st] = 1;
	if(st == des){//找到终点 
		rec[des]++;
		int tt = st;
		while(pre[tt] != tt){ //把起点到终点之间所有节点访问次数+1 
			rec[pre[tt]]++;
			tt = pre[tt];
		}
		vis[st] = 0;
		return;
	}
	for(int i = 0;i < vc[st].size();i++){
		int t;
		t = vc[st][i];
		if(!vis[t]){
			pre[t] = st;
			dfs(t);
			vis [t] = 0;
			pre[t] = 0;
		}
	}
}

int main(){
	int n,m;
	cin>>n>>m;
	for(int i = 0;i < m;i++){
		int a,b;
		cin>>a>>b;
		vc[a].push_back(b);
		vc[b].push_back(a);
	}
	cin>>st>>des;
	pre[st] = st;
	dfs(st);
	if(rec[des] == 0){ //终点没有被访问过 
		cout<<-1;
		return 0;
	}
	for(int i = 1;i <= n;i++){
		if(i != des && i != st){
			if(rec[i] == rec[des]){ //找节点访问次数等于终点访问次数的,即为割点 
				num++;
			}
		}
	}
	cout<<num; 
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_39909619/article/details/88556834