嗅探器

https://loj.ac/problem/10101

题目描述

  给出一张无向图和两个点a、b,求是否能找出一个点使得a到b的所有路径都要经过这个点。

思路

  路径都必须经过,很容易想到割点。但由于要求的是a到b的路径中,那么就有几种情况:

  ①若a、b在同一个点双联通分量中,显然不存在这样一个节点。

  ②若a、b不在一个点双联通分量中,那么我们可以选择缩点后两点所在分量的树上简单路径上的所有割点。

  因此我们只需要tarjan(a),以a为根搜索下去,在判断割点u(u不为树根)时加上条件dfn[b]≥dfn[v]即可,意味着b在v的搜索次序后,那么显然就可以通过这个割点来监视所有情报。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=110,M=N*N;

struct Edge
{
    int to,nxt;
}e[M];

int nxt[M],to[M],tot,head[N];
void add_edge(int x,int y)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
}

int poi[N],tt;
void add(int x,int y)
{
    e[++tt].nxt=poi[x];
    poi[x]=tt;
    e[tt].to=y;
}

int dfn[N],low[N],idx,root,ans=0x7fffffff,a,b;
void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
            if(root!=u&&dfn[u]<=low[v]&&dfn[b]>=dfn[v])
                ans=min(ans,u);
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
int main() 
{
    int n;
    scanf("%d",&n);
    int x,y;
    while(scanf("%d%d",&x,&y)&&(x|y))
    {
        add_edge(x,y);
        add_edge(y,x);
    }
    scanf("%d%d",&a,&b);
    root=a;
    tarjan(a);
    if(ans!=0x7fffffff)
        printf("%d",ans);
    else printf("No solution");
}

猜你喜欢

转载自www.cnblogs.com/fangbozhen/p/11741038.html