-
- 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 "); return 0; } if (!bfs2()) printf("-1 "); return 0; }