信息学奥赛一本通 1523:嗅探器 | 洛谷 P5058 [ZJOI2004]嗅探器

【题目链接】

ybt 1523:嗅探器
洛谷 P5058 [ZJOI2004]嗅探器

【题目考点】

1. 图论:割点

【解题思路】

每个服务器是一个顶点,服务器之间的连接关系是边。
记两个蓝军的信息中心的顶点编号分别为st与ed。
思考从顶点st(一个蓝军信息中心)出发,进行深搜,得到DFS生成树,树根是st。
嗅探器的位置,只可能是在图中的割点位置。但不是每个割点都适合放嗅探器。

使用tarjan算法求割点:
首先不能考虑根结点是割点的情况,根结点st是蓝军信息中心,红军的嗅探器只能放在中间服务器上,不能放在信息中心。同理,嗅探器也不能放在ed。
假设合理的可以作为嗅探器的割点为u,删掉u后,st与ed必然存在于两个不同的连通分量。
因此,如果可以在u处放嗅探器,信息中心ed必然应该在DFS生成树中的以割点u为根结点的子树中。
在从u出发访问邻接点v时,满足dfn[u] <= low[v],确定了u是割点。此时dfn[u], dfn[v], dfn[ed]之间有3种情况。
信息学奥赛一本通 1523:嗅探器 | 洛谷 P5058 [ZJOI2004]嗅探器_第1张图片

  1. dfn[ed] < dfn[u],即先访问ed,再访问u,那么st到ed一定有不经过u的路径,删掉顶点u后不能让st与ed处于不同的连通分量。。
  2. dfn[u] < dfn[ed] < dfn[v],假设以u的孩子ve为根结点的子树中包含ed(ve可能就是ed),
    • 如果在访问u的邻接点ve时,满足dfn[u] <= low[ve],判断出u是割点。那么就已经满足下面的第3种情况了,会把顶点u作为可以放嗅探器的顶点。
    • 如果以ve为根结点的子树中存在某条回边可以回到比u更早的顶点,那么一定不满足dfn[u] <= low[ve],u不是割点,ed与st有不通过u的路径。因此u也不能作为嗅探器的安放点。
  3. dfn[v] <= dfn[ed]。这时ed一定在以v为根结点的子树上(如果ed在u的其它未访问的子树中,那么还没有访问到ed,dfn[ed]为0,则不可能满足该表达式。)
    这时删除割点u,st与ed一定处于不同的连通分量。

因此一个顶点u可以放嗅探器的条件为:u是割点(满足dfn[u] <= low[v]),不是蓝军信息中心st或ed,且满足dfn[v] <= dfn[ed]

从顶点S出发,调用tarjan算法,求出图中的割点,判断该割点是否可以放嗅探器。
求所有满足条件的可以放嗅探器的顶点的最小值,即为结果。
如果表示嗅探器顶点的变量未被赋值,输出“无方案”。

【题解代码】

#include
using namespace std;
#define N 200005
#define INF 0x3f3f3f3f
int n, st, ed; 
vector<int> edge[N];
int dfn[N], low[N], ts, cutVer = INF;
void tarjan(int u)
{
	dfn[u] = low[u] = ++ts;
	for(int v : edge[u])
	{
		if(dfn[v] == 0)
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
			if(u != st && u != ed && dfn[u] <= low[v] && dfn[v] <= dfn[ed])
				cutVer = min(cutVer, u);
		}
		else
			low[u] = min(low[u], dfn[v]);
	}
}

int main()
{
	int f, t;
	cin >> n;
	while(cin >> f >> t && f && t)
	{
		edge[f].push_back(t);
		edge[t].push_back(f);
	}
	cin >> st >> ed;
	tarjan(st);//根据题意,蓝军两个信息中心一定在一个连通图中。只需要从st出发进行搜索 
	if(cutVer == INF) 
		cout << "No solution";
	else
		cout << cutVer;
	return 0;
}

你可能感兴趣的:(信息学奥赛一本通题解,洛谷题解,算法,图论)