luogu P5058 [ZJOI2004]嗅探器 |Tarjan

题目描述

某军搞信息对抗实战演习,红军成功地侵入了蓝军的内部网络,蓝军共有两个信息中心,红军计划在某台中间服务器上安装一个嗅探器,从而能够侦听到两个信息中心互相交换的所有信息,但是蓝军的网络相当的庞大,数据包从一个信息中心传到另一个信息中心可以不止有一条通路。现在需要你尽快地解决这个问题,应该把嗅探器安装在哪个中间服务器上才能保证所有的数据包都能被捕获?

输入格式

输入文件的第一行一个整数 n,表示蓝军网络中服务器的数目。

接下来若干行是对蓝军网络的拓扑结构描述,每行是两个整数 i , j 表示编号为 i 和编号为 j 的两台服务器间存在连接(显然连接是双向的),服务器的编号从 1 开始,一行两个 0 表示网络的拓补结构描述结束,再接下来是两个整数 a , b 分别表示两个中心服务器的编号。

输出格式

输出编号。如果有多个解输出编号最小的一个,如果找不到任何解,输出 No solution

Tarjan求割点,把按序号尝试把割点删掉,判断是否联通

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int next[N*2],head[N],go[N*2],tot;
inline void add(int u,int v){
	next[++tot]=head[u];head[u]=tot;go[tot]=v;
	next[++tot]=head[v];head[v]=tot;go[tot]=u;
}
int dfn[N],low[N],st[N],top,num,root;
int cnt[N];
inline void Tarjan(int u){
	dfn[u]=low[u]=++num;
	int flag=0;
	for(int i=head[u];i;i=next[i]){
		int v=go[i];
		if(!dfn[v]){
			Tarjan(v);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				flag++;
				if(u!=root||flag>1)cnt[u]=1;
			}
		}else
		low[u]=min(low[u],dfn[v]);
	}
}
int n,s,ed;
int dis[N];
bool vis[N];

inline bool bfs(int x){
	memset(vis,0,sizeof(vis));
	queue<int>q;
	vis[s]=vis[x]=1;
	q.push(s);
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=next[i]){
			int v=go[i];
			if(v==ed)return 0;
			if(!vis[v])vis[v]=1,q.push(v);
		}
	}
	return 1;
}
signed main(){
	cin>>n;
	while(1){
		int u,v;
		scanf("%d%d",&u,&v);
		if(u==0&&v==0)break;
		add(u,v);
	}
	cin>>s>>ed;
	root=s;
	Tarjan(s);
	for(int i=1;i<=n;i++)
	if(cnt[i]){
		if(bfs(i)){
			printf("%d\n",i);
			return 0;
		}
	}
	printf("No solution\n");
}
posted @ 2019-10-22 20:09  白木偶君  阅读(144)  评论(0编辑  收藏  举报