1. 程式人生 > >NOIP2014提高組-day2-2——尋找道路(。。。。這算什麼題呢。。?最短路?)

NOIP2014提高組-day2-2——尋找道路(。。。。這算什麼題呢。。?最短路?)

在有向圖G中,每條邊的長度均為1,現給定起點和終點,請你在圖中找一條從起點到終點的路徑,該路徑滿足以下條件: 1.路徑上的所有點的出邊所指向的點都直接或間接與終點連通。 2.在滿足條件1的情況下使路徑最短。 注意:圖G中可能存在重邊和自環,題目保證終點沒有出邊。 請你輸出符合條件的路徑的長度。 輸入 第一行有兩個用一個空格隔開的整數n和m,表示圖有n個點和m條邊。    接下來的m行每行2個整數x、y,之間用一個空格隔開,表示有一條邊從點x指向點y。 最後一行有兩個用一個空格隔開的整數s、t,表示起點為s,終點為t。 輸出 輸出只有一行,包含一個整數,表示滿足題目描述的最短路徑的長度。如果這樣的路徑不存在,輸出- 1。 樣例輸入 3 2 1 2 2 1 1 3

road.in 6 6 1 2 1 3 2 6 2 5 4 5 3 4 1 5 樣例輸出 -1 樣例2: road.out 3

考慮到所有點的出邊都必須和終點相連

那我們在建有向圖的時候也建一個反向圖

那我們可以先從終點沿反向圖dfs一次,把所有能走到的點標出來

然後從起點開始跑最短路

每次對於一個新的點,我們先列舉其所有出去的點,如果有的點沒有被標出來

那麼這個點顯然是不能走

continue就可以了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
    char
ch=getchar(); int res=0; while(!isdigit(ch))ch=getchar(); while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return res; } const int N=10005; const int M=200005; int n,m,adj[N],nxt[M],to[M],dis[N],head[N],go[M],nec[M],str,des,cnt,tot; bool vis[N],pas[N]; inline void addedge
(int u,int v){ nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v; nec[++tot]=head[v],head[v]=tot,go[tot]=u; } inline void dfs(int u){ for(int e=head[u];e;e=nec[e]){ int v=go[e]; if(pas[v])continue; pas[v]=true; dfs(v); } } priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q; inline void dijkstra(){ memset(dis,127,sizeof(dis)); q.push(make_pair(0,str));dis[str]=0; while(!q.empty()){ int u=q.top().second;q.pop(); if(vis[u])continue;vis[u]=true; bool flag=true; for(int e=adj[u];e;e=nxt[e]){ int v=to[e]; if(!pas[v])flag=false; } if(!flag)continue; for(int e=adj[u];e;e=nxt[e]){ int v=to[e]; if(dis[u]+1<dis[v]){ dis[v]=dis[u]+1; q.push(make_pair(dis[v],v)); } } } } int main(){ n=read(),m=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(); addedge(u,v); } str=read(),des=read();pas[des]=1; dfs(des); dijkstra(); if(dis[des]<1000000000) cout<<dis[des]; else cout<<"-1"; }