NOIP2014 寻找道路
题目描述 Description
在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。
注意:图G中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入描述 Input Description
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。
输出描述 Output Description
输出文件名为road.out。
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。
样例输入 Sample Input
road.in |
road.out |
3 2 1 2 2 1 1 3 |
-1 |
样例输出 Sample Output
road.in |
road.out |
6 6 1 2 1 3 2 6 2 5 4 5 3 4 1 5 |
3 |
数据范围及提示 Data Size & 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。
思路:
分析问题,做的最短路中的点既能从起点出发,又能从终点回来,所以先预处理,有两种方式,可以先在起点进行一遍bfs,把在没到终点前就没有出边的点标记下,然后再沿着反图进行一遍bfs,或者可以直接从终点出发在反图进行一遍bfs,把没涉及到的点标出来,然后再在反图bfs,最后最短路
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<algorithm> using namespace std; const int maxn = 200005,maxnum = 100000; int dist[maxn],jud[maxn],q[maxn],start[maxn],tnum[maxn],fjud[maxn],cuter[maxn],n,m,x,t,ans,num = 0; struct star{ int next; int to; int p; }; star edge[maxn]; void dfs(int node){ int head = 1,tail = 1,bq[maxn]; fjud[node] = 0; bq[1] = node; while(head <= tail){ int now = bq[head]; for(int i = start[now];i != -1;i = edge[i].next){ if(fjud[edge[i].to]){ tail = (tail + 1) % maxn; bq[tail] = edge[i].to; fjud[edge[i].to] = 0; } } head = (head + 1) % maxn; } } void dfs1(int node){ int head = 1,tail = 1,bq[maxn]; cuter[node] = 0; bq[1] = node; while(head <= tail){ int now = bq[head]; for(int i = start[now];i != -1;i = edge[i].next){ if(cuter[edge[i].to]){ bq[tail] = edge[i].to; cuter[edge[i].to] = 0; } } head = (head + 1) % maxn; } } int spfa(int u,int v){ dist[u] = jud[u] = 0; q[1] = u; int head = 1,tail = 1; while(head <= tail){ int now = q[head]; for(int i = start[now];i != -1;i = edge[i].next){ if(dist[edge[i].to] > dist[now] + edge[i].p && cuter[edge[i].to]){ dist[edge[i].to] = dist[now] + edge[i].p; if(jud[edge[i].to]){ tail = (tail + 1) % maxn; q[tail] = edge[i].to; jud[edge[i].to] = 0; } } } head = (head + 1) % maxn; jud[now] = 1; } if(dist[v] == 100000) return -1; return dist[v]; } int main(){ cin>>n>>m; int u,v,p; for(int i = 1;i <= n;i++){ start[i] = -1; dist[i] = maxnum; jud[i] = 1; fjud[i] = 1; cuter[i] = 1; tnum[i] = 0; } int cnt = 1; for(int i = 1;i<= m;i++){ cin>>u>>v; swap(u,v); edge[i].p = 1; edge[i].to = v; edge[i].next=start[u]; cnt++; start[u] = cnt - 1; tnum[u]++; } cin>>x>>t; dfs(t); for(int i = 1;i <= n;i++) if(fjud[i]) dfs1(i); cuter[x]= cuter[t] = 1; ans = spfa(t,x); cout<<ans; return 0; }