【NOIP2014】尋找道路
Description
在有向圖 G 中,每條邊的長度均爲 1,現給定起點和終點,請你在圖中找一條從起點到 終點的路徑,該路徑滿足以下條件:
路徑上的所有點的出邊所指向的點都直接或間接與終點連通。
在滿足條件 1 的情況下使路徑最短。
注意:圖 G 中可能存在重邊和自環,題目保證終點沒有出邊。 請你輸出符合條件的路徑的長度。
Input
第一行有兩個用一個空格隔開的整數 n 和 m,表示圖有 n 個點和 m 條邊。
接下來的 m 行每行 2 個整數 x、y,之間用一個空格隔開,表示有一條邊從點 x 指向點y。
最後一行有兩個用一個空格隔開的整數 s、t,表示起點爲 s,終點爲 t。
Output
輸出只有一行,包含一個整數,表示滿足題目描述的最短路徑的長度。
如果這樣的路徑不存在,輸出-1。
Sample Input
樣例1:
3 2
1 2
2 1
1 3
樣例2:
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
Sample Output
樣例1:
-1
樣例2:
3
Hint
對於 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。
提示
【輸入輸出樣例1說明】
如上圖所示,箭頭表示有向道路,圓點表示城市。起點 1 與終點 3 不連通,所以滿足題目描述的路徑不存在,故輸出-1。
【輸入輸出樣例2說明】
如上圖所示,滿足條件的路徑爲 1->3->4->5。注意點 2 不能在答案路徑中,因爲點 2 連了一條邊到點 6,而點 6 不與終點 5 連通。
Source
NOIP2014 提高組 Day2
圖論,最短路
Solution
第一遍bfs從終點開始反向遍歷所有終點可以到的點將之記錄
第二遍bfs從起點開始正向找最短路徑並滿足該路徑所有的點皆被標記(即通往終點)
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define M 200010
#define N 10010
#define inf 1000000009
#define LL long long
using namespace std;
struct node {
int nxt, to;
} e[M << 1];
int n, m, a, b, s, t, head[N], u[M], v[M], cnt, q[N], dis[N];
bool vis[N];
inline void add(int a, int b) {
e[++cnt].nxt = head[a], e[cnt].to = b, head[a] = cnt;
}
inline void bfs1() {
int h = 0, tail = 1;
q[0] = t, vis[t] = 1;
while (h != tail) {
int now = q[h++];
for (int i = head[now]; i; i = e[i].nxt)
if (!vis[e[i].to])
vis[e[i].to] = 1, q[tail++] = e[i].to;
}
}
inline bool check(int x) {
for (int i = head[x]; i; i = e[i].nxt)
if (!vis[e[i].to]) return 0;
return 1;
}
inline bool bfs2() {
int h = 0, tail = 1;
q[0] = s, dis[s] = 0;
while (h != tail) {
int now = q[h++];
if (!check(now)) continue;
for (int i = head[now]; i; i = e[i].nxt)
if (dis[e[i].to] == -1) {
dis[e[i].to] = dis[now] + 1;
q[tail++] = e[i].to;
if (e[i].to == t) {printf("%d\n", dis[t]); return 1;}
}
}
return 0;
}
int main(){
freopen("CJOJ1283.in", "r", stdin);
freopen("CJOJ1283.out", "w", stdout);
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++i) scanf("%d %d", &u[i], &v[i]), add(v[i], u[i]);
scanf("%d %d", &s, &t);
bfs1(), cnt = 0;
memset(head, 0, sizeof(head));
memset(dis, -1, sizeof(dis));
for (int i = 1; i <= m; ++i) if (u[i] != v[i]) add(u[i], v[i]);
if (!vis[s]) {printf("-1\n"); return 0;}
if (!bfs2()) {printf("-1\n"); return 0;}
return 0;
}
Summary
一開始沒有讀懂題,以爲只要求兩點間的最短路就可以了,後來才意識到題目的意思……