寻找道路
题目描述:
有点的出边所指向的点都直接或间接与终点连通。
2 .在满足条件1 的情况下使路径最短。
注意:图G 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入格式:
第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边。
接下来的m 行每行2 个整数x 、y ,之间用一个空格隔开,表示有一条边从点x 指向点y 。
最后一行有两个用一个空格隔开的整数s 、t ,表示起点为s ,终点为t 。
输出格式:
输出只有一行,包含一个整数,表示满足题目?述的最短路径的长度。如果这样的路径不存在,输出- 1 。
样例输入:
样例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
样例输出:
样例1: -1 样例2: 3
提示:
解释1:
如上图所示,箭头表示有向道路,圆点表示城市。起点1 与终点3 不连通,所以满足题
目?述的路径不存在,故输出- 1 。
解释2:
如上图所示,满足条件的路径为1 - >3- >4- >5。注意点2 不能在答案路径中,因为点2连了一条边到点6 ,而点6 不与终点5 连通。
对于30%的数据,0
对于60%的数据,0
对于100%的数据,0
时间限制:1000ms
空间限制:256MByte
来源:NOIP2014提高t5
俗话说的好啊,现有搜索后有天,反向剪枝日神仙。这题在网上的题解十分多我看了一下,有用栈优化bellman-ford,SPFA,Dijkstra+heap,bellman-ford+stack等等等等,这些我都听不懂。呆滞大佬说,我只要两次bfs就可以搞定。关于程序中诡异的ti数组和a结构体,详见《联合权值——呆滞大佬der最骚操作?》
http://www.cnblogs.com/cain-/p/7306003.html
#include<bits/stdc++.h> #include<bits/stdc++.h> using namespace std; struct nob{ int sta,ed; }a[200005]; bool mmp(nob a,nob b){ return a.ed<b.ed; } int n,m,has[100005]={0},has1[100005]={0},s[1000001]={0},ti[200005]={0},start,finish,step[200005]={0}; int main(){ cin>>n>>m; for (int i=1; i<=m; i++){ cin>>a[i].sta>>a[i].ed; ti[a[i].ed]++; }//这里是不是觉得有点奇怪 for (int i=1; i<=n; i++) ti[i]+=ti[i-1]; cin>>start>>finish; sort(a+1,a+1+m,mmp); int head=0,tail=1; s[1]=finish;//从尾巴开始找 has[finish]=1; while (head<tail){ head++; for (int i=ti[s[head]-1]+1; i<=ti[s[head]]; i++){ if (has[a[i].sta]==0){ has[a[i].sta]=1; tail++; s[tail]=a[i].sta; } } }//找出不能到达的点 for (int i=1; i<=n; i++){ if (has[i]==0){ has1[i]=1; for (int l=ti[i-1]+1; l<=ti[i]; l++){ has1[a[l].sta]=1; } } }//用不能到达的点来反向标记他的父亲,表示父亲节点有子节点没有直接或间接地指向终点 head=0;tail=1; s[1]=finish; has1[finish]=1; while (head<tail){ head++; if (s[head]==start){ cout<<step[s[head]]; return 0; } for (int i=ti[s[head]-1]+1; i<=ti[s[head]]; i++){ if (has1[a[i].sta]==0){ has1[a[i].sta]=1; tail++; s[tail]=a[i].sta; step[a[i].sta]=step[a[i].ed]+1; } } }//再次广搜找出答案 cout<<-1; return 0; }
参考了联合权值那道题目之后你会发现这个有些奇怪,那就对了,这就是传说中最难以预判的剪枝,倒搜剪枝!用正着搜索的话即使用同样的方法还是过不了的,然后我们再来仔细地研究一下这个代码,就会发现这里用了两次广搜,第一次广搜看上去是将能够到达的点标记,实质上是遍历has数组将不能到达的点找出来,找到不能到达的点之后再在has1数组中将他的父亲节点和他自己标记起来表示这些点不能走。然后就可以完成这道题目啦。