洛谷P1807 最长路_NOI导刊2010提高(07)
图论
求有向无环图的 最长路
首先阐明一点
最长路dijkstra 是不能做
(当然我是不会做的,不过我貌似看到过网上的dalao有用dijstra做的)
为什么dijstra难做呢(或者说不大好做呢)
这是因为,Dijkstra算法的大致思想是每次选择距离源点最近的结点加入,
然后更新其它结点到源点的距离,直到所有点都被加入为止。当每次选择最短
的路改为每次选择最长路的时候,出现了一个问题,那就是不能保证现在加入
的结点以后是否会被更新而使得到源点的距离变得更长,而这个点一旦被选中
将不再会被更新。例如这次加入结点u,最长路为10,下次有可能加入一个结
点v,使得u通过v到源点的距离大于10,但由于u在之前已经被加入到集合中,
无法再更新,导致结果是不正确的。
如果取反用dijkstra求最短路径呢,记住,dijkstra不能计算有负边的情况。。。
1、一种做法是拓扑排序之后再动态规划
2、还有一种做法就是 直接SPFA求最长路,
但是需要注意点不出队列,这样防止出现正环之后死循环
总结一下求最长路径的方法
首先对于最长路径可以分类
1、可以重复走
这个可以用SPFA 或者 floyd 来求 方法类似
2、不能重复走
这是个NP-hard 直接dfs暴搜
因为每个边只能走一次,你用SPFA就得用f 标记,
然后对于不同路径f数组还不一样,所以SPFA不可做 (也许可做,但我不会QwQ)
但是如果再加上一些特殊的条件
比如说是有向无环图
这个就可做了
1、一种方法拓扑排序一下 跑动态规划
2、或者直接记忆化搜索
3、或者直接SPFA 或者 floyd
SPFA 其实很好改 松弛的时候条件变一下,然后dist初始值变一下就行了
另一个人的博客
1。 肯定不能用dijkstra算法,这是因为,Dijkstra算法的大致思想是每次选择距离源点最近的结点加入,然后更新其它结点到源点的距离,直到所有点都被加入为止。当每次选择最短的路改为每次选择最长路的时候,出现了一个问题,那就是不能保证现在加入的结点以后是否会被更新而使得到源点的距离变得更长,而这个点一旦被选中将不再会被更新。例如这次加入结点u,最长路为10,下次有可能加入一个结点v,使得u通过v到源点的距离大于10,但由于u在之前已经被加入到集合中,无法再更新,导致结果是不正确的。
如果取反用dijkstra求最短路径呢,记住,dijkstra不能计算有负边的情况。。。
2.
可以用 Bellman-Ford 算法求最长路径,只要把图中的边权改为原来的相反数即可。也可以用Floyd-Warshall 算法求每对节点之间的最长路经,因为最长路径也满足最优子结构性质,而Floyd算法的实质就是动态规划。但是,如果图中含有回路,Floyd算法并不能判断出其中含有回路,且会求出一个错误的解;而Bellman-Ford算法则可以判断出图中是否含有回路。
3. 如果是有向无环图,先拓扑排序,再用动态规划求解。
1 #include <cstdio> 2 #include <cmath> 3 #include <cstdlib> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 #include <iomanip> 9 #include <queue> 10 using namespace std ; 11 12 const int maxn = 1511,maxm = 50011 ; 13 struct node{ 14 int to,val,pre ; 15 }e[maxm]; 16 int n,m,x,y,val,cnt ; 17 int dist[maxn],vis[maxn],head[maxn] ; 18 queue <int> Q ; 19 20 inline void add(int x,int y,int v) 21 { 22 e[++cnt] = (node){ y,v,head[x] } ; 23 head[x] = cnt ; 24 } 25 26 inline void SPFA(int s,int t) 27 { 28 int u,v ; 29 for(int i=1;i<=n;i++) 30 dist[ i ] = -1 ; 31 dist[ 1 ] = 0 ; 32 vis[ 1 ] = 1 ; 33 Q.push(1) ; 34 while(!Q.empty()) 35 { 36 u = Q.front() ; 37 Q.pop() ; 38 // 39 for(int i=head[u];i;i=e[i].pre) 40 { 41 v = e[ i ].to ; 42 if(dist[ u ]+e[ i ].val > dist[ v ]) 43 { 44 dist[ v ] = dist[ u ] + e[ i ].val ; 45 Q.push(v) ; 46 //if(!vis[ v ]) Q.push(v),vis[ v ] = 1 ; 47 } 48 } 49 //vis[ u ] = 0 ; 50 } 51 printf("%d ",dist[ n ]) ; 52 } 53 54 int main() 55 { 56 scanf("%d%d",&n,&m) ; 57 for(int i=1;i<=m;i++) 58 scanf("%d%d%d",&x,&y,&val),add(x,y,val) ; 59 if(n==1) 60 { 61 printf("0 ") ; 62 return 0 ; 63 } 64 SPFA(1,n) ; 65 return 0 ; 66 }