【蓝桥杯】 历届试题 危险系数(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



---分割线---



分析:
显然本题是让你求一个通路中的割点数,第一反应自然地想到了特洛伊算法
但是这数据的规模最大可到1000,显然这个复杂度到了O(N^3)的算法会超时,pass
现在我们把重点放在割点,怎么样求割点?
先把样例数据构成的图像画出,如下:

在这里插入图片描述
我们来看一下所有的通路数和割点之间有什么关系,得到以下通路:
通路1:1->3->5->6
通路2: 1->3->4->5->6
而对于其中的割点,通过画图不难发现其中的割点有:3、5
于是可以得到一个关于通路和割点之间的关系:
每一条从起点到终点的路径(除起点和终点外),其每个割点出现的次数相同,并且等于所有通路的数量
(上述的样例数据或许偏少,但你可以多构造几组试试,你会发现上述定理依然是成立的)

由此便得到一个解题思路:
先用dfs进行搜索,统计出从给定起点到终点的通路数量sum,并在每一次到达了目标终点时,把该路径上的所有节点都保存在另一个用于记录每个节点出现次数的数组def中。当dfs寻路结束之后,用一个循环对该数组进行判断,若满足sum==def[i],则说明该点是一个割点,此时ans++。最后,只要ans>1(注意def[终点]肯定是等于sum的,而def[起点]在dfs中是没有被纳入统计之中,因此ans需要大于1才能说明有割点),且输出为ans-1(由于dfs也把终点给统计进去了,故你需要把这个终点给删除)

下面给出本题的完整代码:


---分割线---


#include<iostream>
#include<vector>
using namespace std; 

int n,m;			//点以及边信息
int map[1010][1010];//图的邻接矩阵表示
int def[1010];		//用于表示某个点在路径中出现了几次 
int vis[1010];		//visited表示某个点是否已经走过了
int sum=0;			//用于统计有多少条从起点到终点的路 
vector <int> v;		//用于放置某条通路中的所有点信息

void dfs(int cur,int tar)
{
	if(cur==tar)
	{
		sum++;						//通路数量增加
		for(int i=0;i<v.size();i++) //因为需要对每个路径上的点做处理,因此选择的是vector
			 def[v[i]]++;			//通路上的每个点都记录下来
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i]==0 && map[cur][i])//未访问,并且存在通路则前进
		{
			v.push_back(i);		//入栈 
			vis[i]=1;			//标记该点为已访问 
			dfs(i,tar);			//进入下一个点继续搜索
			vis[i]=0;			//回退 
			v.pop_back();		//出栈 
		}
	}
} 

int main()
{
	cin>>n>>m;
	int a,b,ans=0;
	for(int i=0;i<m;i++)
	{
		cin>>a>>b;
		map[a][b]=map[b][a]=1;
	}
	int beg,tar;			//分别表示目标和终点
	cin>>beg>>tar;   
	vis[beg]=1;				//这里把vis[beg]标记为已访问,那么接下来的dfs中将不会统计beg这个点
	dfs(beg,tar); 
	for(int i=1;i<=n;i++)
		if(def[i]==sum)
			ans++; 
	if(ans>1)
		cout<<ans-1<<endl;	//注意需要减去起点那个点本身 
	else
		cout<<-1<<endl;
	return 0;
}

发布了30 篇原创文章 · 获赞 67 · 访问量 3053

猜你喜欢

转载自blog.csdn.net/the_ZED/article/details/100123624
今日推荐