1807. [NOIP2014]寻找道路P2296 寻找道路
题目描述
在有向图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 。
输入输出样例
输入样例#1:
3 2 1 2 2 1 1 3
输出样例#1:
-1
输入样例#2:
6 6 1 2 1 3 2 6 2 5 4 5 3 4 1 5
输出样例#2:
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。
这道题我们可以用逆向思维来想
如果一个点能到达终点,那么终点也一定能到达这个点
这样就简单了
从终点跑一遍BFS,算出每一个点的访问次数
然后把不能走的点删去
最后spfa带走
一个很有意思的能够找出访问次数而且不会死循环的方法
1 int to=edge[i].v;
2 if(cs[to]++)continue;
3 q.push(to);
完整代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<queue> 6 #define INF 0x7ffffff 7 using namespace std; 8 int read(int & n) 9 { 10 int flag=0,x=0;char c='/'; 11 while(c<'0'||c>'9'){c=getchar();if(c=='-')flag=1;} 12 while(c>='0'&&c<='9')x=x*10+(c-48),c=getchar(); 13 if(flag)n=-x;else n=x; 14 } 15 const int MAXN=200001; 16 int n,m,bgx,bgy; 17 int rudu[MAXN]; 18 struct node 19 { 20 int u,v,w,nxt; 21 }edge[MAXN]; 22 int num=1; 23 int head[MAXN]; 24 int flag[MAXN];// 记录每个值是否能够到达终点 25 int cs[MAXN]; 26 int dis[MAXN]; 27 int vis[MAXN]; 28 void add_edge(int ll,int rr,int ww) 29 { 30 edge[num].u=ll; 31 edge[num].v=rr; 32 edge[num].w=ww; 33 edge[num].nxt=head[ll]; 34 head[ll]=num++; 35 } 36 void bfs() 37 { 38 queue<int>q; 39 int tot=0; 40 q.push(bgx),tot++; 41 while(q.size()!=0) 42 { 43 int p=q.front(); 44 q.pop(); 45 for(int i=head[p];i!=-1;i=edge[i].nxt) 46 { 47 int to=edge[i].v; 48 if(cs[to]++)continue; 49 q.push(to); 50 } 51 } 52 //rudu[bgy]=0; 53 for(int i=1;i<=n;i++) 54 if(rudu[i]!=cs[i]&&i!=bgy) 55 flag[i]=1; 56 } 57 void dele() 58 { 59 for(int i=1;i<=num;i++) 60 { 61 if(flag[edge[i].u]!=0) 62 { 63 edge[i].u=-1; 64 edge[i].v=-1; 65 edge[i].w=-1; 66 edge[i].nxt=-1; 67 } 68 } 69 } 70 void spfa() 71 { 72 queue<int>q; 73 q.push(bgx); 74 dis[bgx]=0; 75 while(q.size()!=0) 76 { 77 int p=q.front(); 78 q.pop(); 79 vis[p]=0; 80 for(int i=head[p];i!=-1;i=edge[i].nxt) 81 { 82 if(edge[i].u==-1)continue; 83 int to=edge[i].v; 84 if(dis[to]>dis[p]+edge[i].w) 85 { 86 dis[to]=dis[p]+edge[i].w; 87 if(vis[to]==0) 88 { 89 vis[to]=1; 90 q.push(to); 91 } 92 } 93 } 94 } 95 if(dis[bgy]==INF) 96 printf("-1"); 97 else 98 printf("%d",dis[bgy]); 99 } 100 int main() 101 { 102 freopen("roadb.in","r",stdin); 103 freopen("roadb.out","w",stdout); 104 read(n);read(m); 105 for(int i=1;i<=n;i++)head[i]=-1,dis[i]=INF; 106 for(int i=1;i<=m;i++) 107 { 108 int x,y; 109 read(x);read(y); 110 add_edge(y,x,1); 111 rudu[x]++; 112 } 113 read(bgy);read(bgx); 114 bfs(); 115 dele(); 116 spfa(); 117 return 0; 118 }
作者:自为风月马前卒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。