CJOJ 1283【NOIP2014】尋找道路

【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說明】
Pic
如上圖所示,箭頭表示有向道路,圓點表示城市。起點 1 與終點 3 不連通,所以滿足題目描述的路徑不存在,故輸出-1。
【輸入輸出樣例2說明】
Pic
如上圖所示,滿足條件的路徑爲 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

一開始沒有讀懂題,以爲只要求兩點間的最短路就可以了,後來才意識到題目的意思……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章