**问题描述 **
抗日战争时期,冀中平原的地道战曾发挥重要作用。
地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。
我们来定义一个危险系数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,否则对一任意的一个不是询问点的点,我们要将这个点以及所有的与它直接相连的边去点之后再判断整个图的连通性,如果此时两个询问点不联通的话,那么相当于这个点为关键点。
代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int n,m;
int road[2002][2002];
int pre[2002];
void init()
{
for(int i=1; i<=n; i++)
pre[i]=i;
}
int find_pre(int root)
{
int son,tmp;
son=root;
while(root!=pre[root])
root=pre[root];
while(son!=root) ///压缩路径,将所有节点的父节点都变换成当前的根节点,这样在以后再找的时候就会节省时间
{
tmp=pre[son];
pre[son]=root;
son=tmp;
}
return root;
}
void unin(int x,int y)
{
int px=find_pre(x);
int py=find_pre(y);
if(px!=py)
pre[px]=py;
}
int main()
{
int a,b;
while(~scanf("%d%d",&n,&m))
{
memset(road,0,sizeof(road));
for(int i=0; i<m; i++)
{
scanf("%d%d",&a,&b);
road[a][b]=road[b][a]=1;//标记两点间有路径
unin(a,b);
}
int st,ed;
int ans=0;
scanf("%d%d",&st,&ed);
if(find_pre(st)!=find_pre(ed))//两个询问点本来就不连通
printf("-1\n");
else
{
for(int k=1; k<=n; k++)
{
init();
if(k!=st&&k!=ed)//要遍历所有的非询问点
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(road[i][j]==1&&i!=k&&j!=k)
{
unin(i,j);
}
}
}
if(find_pre(st)!=find_pre(ed))
ans++;
}
}
printf("%d\n",ans);
}
}
return 0;
}