【并查集】嗅探器

嗅探器安装位置算法
本文介绍了一种算法,用于确定在网络中安装嗅探器的最佳位置,以确保捕获两个关键信息中心之间的所有数据包。该算法利用了并查集来高效地检查网络的连通性,并找出必要的割点。

嗅探器

(sniffer.pas/in/out)

Problem

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

Input

第一行一个整数n(1<=n<=100),表示蓝军网络中服务器的数目.

接下来若干行是对蓝军网络的拓扑结构描述.

每行是两个整数i,j表示编号为I和编号为j的两台服务器间存在连接(显然连接是双向的).服务器的编号从1开始.描述以两个0结束.

再接下来一行是两个整数a,b分别表示两个中心服务器的编号.

Output

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

Sample Input

5

2 1

2 5

1 4

5 3

2 3

5 1

0 0

4 2

 

Sample Output

 

1



这道题模型应该是求割点,双连通分量什么的。。

但是考虑到n<=100,我们可以找到替代方法。


根据割点的定义:


在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合。一个图有割点,当且仅当这个图的点连通度为1,则割点集合的唯一元素被称为割点(cut point),又叫关节点(articulation point)


我们可以枚举这个点,然后再判断连通性即可,而且这道题要求判断的是S和T是否在一个连通块里。最优方法是用并查集,它是最符合自然思路的,而且常数最小。而dfs也可以实现。经测试,甚至Floyd也可以满足。

#include <cstdio>
#include <cstring>
#include <string>

bool hash[110][110];
long fa[110];
struct Edge
{
	long u;
	long v;
};
Edge edge[10010];
long cedge = 0;

long getroot(long a)
{
	if (fa[a] == a)
		return fa[a];
	return fa[a] = getroot(fa[a]);
}

void merge(long a,long b)
{
	fa[getroot(a)] = getroot(b);
}

long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp=getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp=='-'){tmp=getchar();sgn=0;}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}

int main()
{
	freopen("sniffer.out","w",stdout);
	freopen("sniffer.in","r",stdin);

	long n = getint();
	while (1)
	{
		long u = getint();
		long v = getint();
		if (u == 0 && v == 0)
			break;
		if (hash[u][v]) continue;
		hash[u][v]=hash[v][u]=true;
		
		++cedge;
		edge[cedge].u = u;
		edge[cedge].v = v;
	}
	
	long s = getint();
	long t = getint();

	for (long p=1;p<n+1;p++)
	{
		if (p == s || p == t) continue;
		for (long i=1;i<n+1;i++)
			fa[i] = i;

		for (long i=1;i<cedge+1;i++)
			if (edge[i].u!=p && edge[i].v!=p)
				merge(edge[i].u,edge[i].v);
		
		if (getroot(s) != getroot(t))
		{
			printf("%ld",p);
			return 0;
		}
	}

	printf("No solution");

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值