嗅探器
(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;
}