1. 程式人生 > >尋找道路 vijos1909 NOIP2014 D2T2 SPFA

尋找道路 vijos1909 NOIP2014 D2T2 SPFA

輸出符 push lin src esp edge temp 我們 opened

在有向圖 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

尋找道路 vijos1909 NOIP2014 D2T2 SPFA