Description
一场大战即将开始…
我们已经掌握了敌人的城市地图,为了在战争中先发制人,决定向敌人的某个城市上空投放炸弹,来切断敌人城市之间的通讯和补给,城市地图如下:
我们可以炸毁2号城市,这样剩下的城市之间就不能两两相护到达了。
Input
第一行有两个整数n,m。n表示有n个顶点,m表示有m条边,
接下来m行,每行形如“a b”表示顶点a和顶点b之间有边。
Output
输出要炸毁的城市。
Sample Input
6 7
1 4
1 3
4 2
3 2
2 5
2 6
5 6
Sample Output
2
#include<iostream>
#include<algorithm>
using namespace std;
int e[9][9],n,m,index,root;//e数组用来存储邻接表 index用来记录时间戳 root用来表示根结点
int num[9],flag[9],low[9];//num数组用来记录当前结点的时间戳 flag数组用来记录割点 low数组用来记录能够到达的最小的时间戳
//这里有一个数据关系当一个结点的能够到达的最小的时间戳小于本身的时间戳时说明在搜索的过程中到达过本结点的之前的结点
//即能够构成一个闭环 而且一个闭环阻断一点仍然是能够通过的 所以是能够判断该结点不是割点的
void dfs(int cur,int father)//传入当前结点和父结点
{int child,i,j;//child用来记录该结点的孩子的个数
index++;//首先时间戳加1
num[cur]=index;//num数组记录时间戳
low[cur]=index;//本结点能到达的最小的时间戳初始化为其本身的时间戳
for(i=1;i<=n;i++)//通过对全部结点的遍历寻找与当前结点有关的结点
{
if(e[cur][i]==1)//当前结点与i结点之间有联系
{
if(num[i]==0)//当i结点时间戳为0,即还没访问过时
{
child++;
dfs(i,cur);//进行下一步深度优先搜索
//通过与新的i结点的最小到达时间戳进行比较,来更新本结点的能够到达最小的时间戳
low[cur]=min(low[cur],low[i]);
//当判断割点时还要分根结点情况和非根结点情况
if(cur!=root&&low[i]>=num[cur])//根据开始的数据结构的分析能够不形成闭环
flag[cur]=1;
}
else if(i!=father)//为了放置无限循环的发生即一直进行向前向后的搜索,这也是深度优先搜索的要求
{
low[cur]=min(low[cur],num[i]);//因为i结点先于cur搜索过了
//该步更新最小时间戳的操作相当与扩大当前结点能够形成的闭环的范围:
//当low[cur]<num[i]时说明本结点能够到达的最小的时间戳比num[i]小即已经形成的闭环比从cur到i形成的闭环要大
//当num[i]<low[cur]时说明本结点还没有形成的闭环或原来的闭环要小于此时新形成的闭环
//
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
e[i][j]=0;//初始化邻接表
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;//建立新的邻接表
e[x][y]=1;
e[y][x]=1;
}
root=1;//建立根结点
dfs(1,root);
for(int i=1;i<=n;i++)
if(flag[i]==1)cout<<i<<" ";
return 0;
}