hdu 3313 Key Vertex BFS应用

该博客讨论了一种寻找有向图中关键点的问题,即删除某些点后使s无法到达t。作者尝试了网络流、标记路径、找割点等方法,最终通过BFS从一条s->t路径出发,寻找满足特定条件的可删除点,即不经过路径上其他点所能到达的最远点。代码实现中,从后向前遍历边以正确找到关键点。
摘要由CSDN通过智能技术生成

题意:给定一个有向图,给一对点(s,t),可删除点的定义为:删除某个点之后使得s没有路径到达t,问有多少个可删除点。


思路:

想法1:

这题一开始我的思路就是用网络流来做。。就是先跑s->t的网络流,若最大流量==1则代表存在关键点,否则不存在关键点(>1和==0的情况分别讨论),然后找关键点就是每次找到可通过的边的最远的那个点开始第二次跑网络流。。之后。。发现不好处理。所以路就断了。。

之后我再想了其他方法来做。

想法2:

就是标记这些点 s-->x--> ...->t 在图中把类似这种的x点标记,建立残图,这个时候残图一定是包含有关s->t的路径的。其他无关路径都没有加进来。再之后把这个有向图给弄成无向图。找割点。割点的个数+2就是答案了。。

后来发现太天真了。

碰到这种结构就完了。。看图。。


红色的点是割点。。但是红色的点并不是关键点。。我就丧心病狂的交了好多发最后还是无情的挂了。。

这种方法不行。。那就换思路吧。。

想法3:

突然想到。。先随意找一条s->t的路径。那么可删除点一定在这条路径上。因为除了这条路径的其他点一定不是可删除点。

那么问题就转换成就找这条路上的关键点。

也就是。假设s->a->b->c->d->e->t是我找的随意一条s->t的有向路径。

这个时候一个点若是可删除点的话那么一定满足这个条件:

从s出发不经过路径上其他点所能到达的最远的点。

看图:


假设我找的一条s->t的路径就是粉色点和黑色点。

这条路径上可删除点就是黑色的点。

每次找一个可删除点。每一次从可删除点为起点开始找下一个可删除点。

以此找下去。。

一开始代码是WA的。。然后观察了大神们的代码之后发现从后面遍历点才AC的。。

真是奇怪。。

for(int i=0;i<(int)e[now].size();i++){

for(int i=e[now].size()-1;i>=0;i--){

在bfs中找最短路有区别吗。。。

代码如下:

//First Edit Time:	2014-11-24 23:53
//Last Edit Time:	2014-11-25 13:18
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cstdlib>
using namespace std;
#define MAXN 100010
int pre[MAXN],vis[MAXN],low[MAXN];
vector <int> e[MAXN];
int bfs1(int st,int et){
    queue <int> q;
    q.push(st);
    vis[st]=1;pre[st]=-1;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=e[now].size()-1;i>=0;i--){
            int next=e[now][i];
            if(vis[next])continue;
            vis[next]=1;
            pre[next]=now;
            if(next==et)return 1;
            q.push(next);
        }
    }
    return 0;
}
int bfs2(int u){
    queue <int> q;
    q.push(u);
    int res=u;
    vis[u]=1;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=e[now].size()-1;i>=0;i--){
            int next=e[now][i];
            if(vis[next])continue;
            vis[next]=1;
            if(low[next]==0)q.push(next);
            else if(low[next]<low[res])res=next;
        }
    }
    return res;
}
int main()
{
    int n,m,st,et;
    while(~scanf("%d%d",&n,&m)){
        for(int i=0;i<=n;i++)
        e[i].clear();
        memset(vis,0,sizeof(vis));
        memset(low,0,sizeof(low));

        for(int i=0,x,y;i<m;i++){
            scanf("%d%d",&x,&y);
            e[x].push_back(y);
        }
        scanf("%d%d",&st,&et);
        if(!bfs1(st,et)){
            printf("%d\n",n);
            continue;
        }

        int u=et,tot=1;
        memset(vis,0,sizeof(vis));
        while(u!=-1){
            low[u]=tot++;
            u=pre[u];
        }
        int cnt=1;
        u=st;
        while(u!=et){
            u=bfs2(u);
            ++cnt;
        }
        printf("%d\n",cnt);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值