## 题目背景
抗日战争时期,冀中平原的地道战曾发挥重要作用。
## 题目描述
地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。
我们来定义一个危险系数 $DF(x,y)$:
对于两个站点 $x$ 和 $y(x\neq y),$ 如果能找到一个站点 $z$,当 $z$ 被敌人破坏后,$x$ 和 $y$ 不连通,那么我们称 $z$ 为关于 $x,y$ 的关键点。相应的,对于任意一对站点 $x$ 和 $y$,危险系数 $DF(x,y)$ 就表示为这两点之间的关键点个数。
本题的任务是:已知网络结构,求两站点之间的危险系数。
## 输入格式
输入数据第一行包含 $2$ 个整数 $n(2 \le n \le 1000)$,$m(0 \le m \le 2000)$,分别代表站点数,通道数。
接下来 $m$ 行,每行两个整数 $u,v(1 \le u,v \le n,u\neq v)$ 代表一条通道。
最后 $1$ 行,两个数 $u,v$,代表询问两点之间的危险系数 $DF(u,v)$。
## 输出格式
一个整数,如果询问的两点不连通则输出 $-1$。
## 样例 #1
### 样例输入 #1
```
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
```
### 样例输出 #1
```
2
```
## 提示
时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛
这题我写的时候思路有,但是代码实现的时候有一个小细节错了,导致全盘皆输55555555555
下面带着大家一起做:
读完题,首先我们会发现题目给了一个网络,也就是一张图,然后一看题目所给的数据量也不大,完全可以用深搜dfs,确定好算法,然后具体分析题目要求。
题目要求找初危险中间节点——也就是去除以后就让图中两点不连通的点。仔细想想,哪些点是不可以去除的中间节点!!聪明的你肯定知道了,如果A -> B, 我们不管走哪一条路径,如果都会通过C,那么C一定是不可去除的!!!所以我们只需要 dfs 找出所有的可达路径,然后把每一条路径的经过点的次数都用sum[]数组记录下来(但是起点和终点不能记录,因为起点终点不是中间节点),只需要for循环查找所有的点,输出与可达路径相同的经过点的数量即可。
知道这个以后,我们就可以写dfs函数了。
!!!
dfs()函数的要点:
1.有vis[]数组
2.进函数之前先将初始点设置为vis[] = true
3.函数内部设置终止条件,即cur = v
4.递归查找前,设置当前点为true,之后,需要回溯,设置当前点为false未访问
5.为保证良好习惯,在main函数内部调用完dfs()之后,也需要设置初始点为false
代码:
#include<bits/stdc++.h>
using namespace std;
bool vis[5000];
int sum[5000];
vector<int> a[1005];
int ans = 0;//表示两点的路径数量
int num = 0;//表示最终结果,危险节点
int m, n;//m个站点,n条边
int u,v;
void dfs(int cur)
{
if(cur == v)//如果查找到终点,就把这条路径上所有访问过的点的访问次数加一
{
ans++;
for(int i = 1; i <= m; i++)
{
if(vis[i])
{
sum[i]++;
}
}
sum[v] = 0;//但是终点不能设置,因为终点不是危险点
sum[u] = 0;//起点也不能设置,因为起点不是危险点
return;
}
for(int i = 0; i < a[cur].size(); i++)
{
int j = a[cur][i];
if(vis[j])
{
continue;
}
vis[j] = true;
dfs(j);
vis[j] = false;
}
}
int main()
{
cin >> m >> n;
for(int i = 1; i <= n; i++)
{
int x, y;
cin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
cin >> u >> v;
vis[u] = true;
dfs(u);
vis[u] = false;
for(int i = 1; i <= m; i++)
{
if(sum[i] == ans)
{
num++;
}
}
if(ans == 0)//如果路径数量为0,表明不连通
{
cout << "-1";
}
else cout << num ;
return 0;
}