-
- 707通過
- 2.6K提交
- 題目提供者該用戶不存在
- 標簽圖論2014NOIp提高組
- 難度普及+/提高
最新討論
題目描述
在有向圖G 中,每條邊的長度均為1 ,現給定起點和終點,請你在圖中找一條從起點到終點的路徑,該路徑滿足以下條件:
1 .路徑上的所有點的出邊所指向的點都直接或間接與終點連通。
2 .在滿足條件1 的情況下使路徑最短。
注意:圖G 中可能存在重邊和自環,題目保證終點沒有出邊。
請你輸出符合條件的路徑的長度。
輸入輸出格式
輸入格式:
輸入文件名為road .in。
第一行有兩個用一個空格隔開的整數n 和m ,表示圖有n 個點和m 條邊。
接下來的m 行每行2 個整數x 、y ,之間用一個空格隔開,表示有一條邊從點x 指向點y 。
最后一行有兩個用一個空格隔開的整數s 、t ,表示起點為s ,終點為t 。
輸出格式:
輸出文件名為road .out 。
輸出只有一行,包含一個整數,表示滿足題目᧿述的最短路徑的長度。如果這樣的路徑不存在,輸出- 1 。
輸入輸出樣例
3 2 1 2 2 1 1 3
-1
6 6 1 2 1 3 2 6 2 5 4 5 3 4 1 5
3
說明
解釋1:

如上圖所示,箭頭表示有向道路,圓點表示城市。起點1 與終點3 不連通,所以滿足題
目᧿述的路徑不存在,故輸出- 1 。
解釋2:

如上圖所示,滿足條件的路徑為1 - >3- >4- >5。注意點2 不能在答案路徑中,因為點2連了一條邊到點6 ,而點6 不與終點5 連通。
對於30%的數據,0<n≤10,0<m≤20;
對於60%的數據,0<n≤100,0<m≤2000;
對於100%的數據,0<n≤10,000,0<m≤200,000,0<x,y,s,t≤n,x≠t。
吐槽:把出邊看漏了,然后就一直WA,把tot忘了清0,i=next[i]寫成了i++,一直RE......
分析:首先,怎么知道一個點i是否與終點連通呢?可以floyd,但是對於這道題就不需要了,從終點反向一次bfs,能標記到的點就是能訪問到的,因為邊權為1,求最短路從起點再來一次bfs即可.每次擴展之前都要先判斷出邊有沒有被標記,從終點bfs了一次過后一定要將用過的數組清0.
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int maxn = 10010, maxm = 200010; int n, m,first,tail,x[maxm],y[maxm],nextt[maxm * 2],to[maxm * 2],head[maxm],tot,s,t,q[maxn],step[maxn]; bool vis[maxn]; void add(int a, int b) { to[++tot] = b; nextt[tot] = head[a]; head[a] = tot; } void bfs1() { q[0] = t; vis[t] = true; first = 0; tail = 1; while (first < tail) { int u = q[first++]; for (int i = head[u];i;i = nextt[i]) { if (!vis[to[i]]) { vis[to[i]] = true; q[tail++] = to[i]; } } } } bool chubian(int q) { for (int i = head[q]; i; i = nextt[i]) if (!vis[to[i]]) return false; return true; } bool bfs2() { first = 0; tail = 1; q[0] = s; step[s] = 0; while (first < tail) { int u = q[first++]; if (!chubian(u)) continue; for (int i = head[u]; i; i = nextt[i]) { if (step[to[i]] == -1) { step[to[i]] = step[u] + 1; q[tail++] = to[i]; if (to[i] == t) { printf("%d", step[to[i]]); return true; } } } } return false; } int main() { memset(vis, false, sizeof(vis)); scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &x[i], &y[i]); add(y[i], x[i]); //反着加便於反着bfs } scanf("%d%d", &s,&t); bfs1(); memset(head, 0, sizeof(head)); memset(step, -1, sizeof(step)); memset(q, 0, sizeof(q)); memset(nextt, 0, sizeof(nextt)); memset(to, 0, sizeof(to)); tot = 0; for (int i = 1; i <= m; i++) add(x[i], y[i]); if (!vis[s]) { printf("-1\n"); return 0; } if (!bfs2()) printf("-1\n"); return 0; }
