传送门:洛谷 P5058
题目描述
某军搞信息对抗实战演习,红军成功地侵入了蓝军的内部网络,蓝军共有两个信息中心,红军计划在某台中间服务器上安装一个嗅探器,从而能够侦听到两个信息中心互相交换的所有信息,但是蓝军的网络相当的庞大,数据包从一个信息中心传到另一个信息中心可以不止有一条通路。现在需要你尽快地解决这个问题,应该把嗅探器安装在哪个中间服务器上才能保证所有的数据包都能被捕获?
输入格式
输入文件的第一行一个整数 n,表示蓝军网络中服务器的数目。
接下来若干行是对蓝军网络的拓扑结构描述,每行是两个整数 i , j 表示编号为 i 和编号为 j 的两台服务器间存在连接(显然连接是双向的),服务器的编号从 1 开始,一行两个 0 表示网络的拓补结构描述结束,再接下来是两个整数 a , b 分别表示两个中心服务器的编号。
输出格式
输出编号。如果有多个解输出编号最小的一个,如果找不到任何解,输出 No solution
输入输出样例
输入 #1
5
2 1
2 5
1 4
5 3
2 3
5 1
0 0
4 2
输出 #1
1
说明/提示
1≤n≤100
题解:
题目可理解为,在图中去掉一个点,使这个原本是一个强连通分量的图变成几个图,且两个信号点不能在一个强连通分量中。
这样的话,就很明显是一个tarjan求割点的问题,那么我们现在的问题就是,如何找到最小的割点,使两个信号点互不相通。
找最小割点我们可以用set来存所有割点,注意到题目的数据范围n最大才100,就想到可以搜索。
从第一个信号点出发,割去割点(即不经过割点),如果仍然可以到达第二个信号点,说明这个割点不符合要求;反之,如果不能到达第二个信号点,说明符合要求。
因为割点用set存,已经排过序,所有一旦搜到直接输出即可。
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=11000;
int n,f,t,k,idx;
int dfn[N],low[N],head[N],vis[N];
set<int> s;
struct edge
{
int to,next;
}e[2*N];
void init()
{
memset(vis,0,sizeof(vis));
}
void add(int u,int v)
{
e[k].to=v;
e[k].next=head[u];
head[u]=k++;
}
void tarjan(int u,int fa)
{
int child=0;
dfn[u]=low[u]=++idx;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]&&u!=fa)
{
s.insert(u);
}
if(u==fa)
{
child++;
}
}
low[u]=min(low[u],dfn[v]);
}
if(u==fa&&child>1)
{
s.insert(u);
}
}
void bfs(int x,int id)
{
queue<int> q;
vis[x]=1;
q.push(x);
while(!q.empty())
{
int p=q.front();
q.pop();
for(int i=head[p];i!=-1;i=e[i].next)
{
int tmp=e[i].to;
if(vis[tmp]) continue;
if(tmp!=id)
{
vis[tmp]=1;
q.push(tmp);
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
k=1,idx=0;
scanf("%d",&n);
int x,y;
while(scanf("%d%d",&x,&y)&&x&&y)
{
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i,i);
}
}
scanf("%d%d",&f,&t);
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++)
{
init();
bfs(f,*it);//从第一个信号器出发,如果不走*it,会经过哪些点
if(!vis[t])//如果不会走到第二个信号器,那么说明*it是我们所要的割点
{
printf("%d\n",*it);
return 0;
}
}
printf("No solution\n");
return 0;
}