寻找道路 vijos1909 NOIP2014 D2T2 SPFA

在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到 终点的路径,该路径满足以下条件:

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
  2. 在满足条件 1 的情况下使路径最短。

注意:图 G 中可能存在重边和自环,题目保证终点没有出边。 请你输出符合条件的路径的长度。

我们存两个图,一个是原图,一个是把原图的边反向后的【反向图】。

我们先用反向图,以目标终点t为起点跑一遍spfa,然后把能跑到的点都记录下来,留待后用。

然后再用正向图(原图),以目标起点s为起点再跑一遍spfa,注意在跑的时候不要跑不满足要求的点

我们用check函数来检验某个点是否符合要求,代码如下。其中able属性是是否在第一次spfa中标记过,若标记过,则为true。

inline bool check(int u)
{
    if(!able[u]) return false;
    for (register int i=head[u];i;i=w[i].next)
        if(!able[w[i].to]) return false;
    return true;
}

 

附上AC代码

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<queue>
  6 #include<iostream>
  7 using namespace std;
  8 template<class T> inline void read(T &_a){
  9     bool f=0;int _ch=getchar();_a=0;
 10     while(_ch<'0' || _ch>'9'){if(_ch=='-')f=1;_ch=getchar();}
 11     while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();}
 12     if(f)_a=-_a;
 13 }
 14 
 15 const int maxn=10001,maxm=200001;
 16 struct edge
 17 {
 18     int to,next;
 19 }w[maxm],w2[maxm];
 20 int n,m,egcnt,egcnt2,head[maxn],head2[maxn],s,t,dis2[maxn],dis[maxn];
 21 queue<int>q;
 22 bool ins[maxn],able[maxn];
 23 
 24 inline void addedge(int from,int to)
 25 {
 26     w[++egcnt].to=to;
 27     w[egcnt].next=head[from];
 28     head[from]=egcnt;
 29     w2[++egcnt2].to=from;
 30     w2[egcnt2].next=head2[to];
 31     head2[to]=egcnt2;
 32 }
 33 
 34 inline void spfa2()
 35 {
 36     q.push(t);
 37     memset(dis2,0x7f,sizeof(dis2));
 38     dis2[t]=0;
 39     while(!q.empty())
 40     {
 41         int now=q.front(); q.pop();
 42         ins[now]=false;
 43         for (register int i=head2[now];i;i=w2[i].next)
 44         {
 45             if(dis2[w2[i].to]>dis2[now]+1)
 46             {
 47                 dis2[w2[i].to]=dis2[now]+1;
 48                 if(!ins[w2[i].to])
 49                 {
 50                     q.push(w2[i].to);
 51                     ins[w2[i].to]=true;
 52                 }
 53             }
 54         }
 55     }
 56 }
 57 
 58 inline bool check(int u)
 59 {
 60     if(!able[u]) return false;
 61     for (register int i=head[u];i;i=w[i].next)
 62         if(!able[w[i].to]) return false;
 63     return true;
 64 }
 65 
 66 inline void spfa()
 67 {
 68     while(!q.empty()) q.pop();
 69     memset(ins,0,sizeof(ins));
 70     q.push(s);
 71     memset(dis,0x7f,sizeof(dis));
 72     dis[s]=0;
 73     while(!q.empty())
 74     {
 75         int now=q.front(); q.pop();
 76         ins[now]=false;
 77         for (register int i=head[now];i;i=w[i].next)
 78             if(check(w[i].to)){
 79             if(dis[w[i].to]>dis[now]+1)
 80             {
 81                 dis[w[i].to]=dis[now]+1;
 82                 if(!ins[w[i].to])
 83                 {
 84                     q.push(w[i].to);
 85                     ins[w[i].to]=true;
 86                 }
 87             }
 88         }
 89     }
 90 }
 91 
 92 int main()
 93 {
 94     read(n); read(m);
 95     for (register int i=1,x,y;i<=m;++i) read(x),read(y),addedge(x,y);
 96     read(s); read(t);
 97     spfa2();
 98     for (register int i=1;i<=n;++i) if(dis2[i]<=n) able[i]=true;
 99     spfa();
100     printf("%d",dis[t]>n?-1:dis[t]);
101     return 0;
102 }
View Code

 

转载于:https://www.cnblogs.com/jaywang/p/7745433.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值