洛谷P1807 最長路_NOI導刊2010提高(07) 求有向無環圖的 最長路 圖論


洛谷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\n",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\n") ; 
62         return 0 ; 
63     }
64     SPFA(1,n) ; 
65     return 0 ;  
66 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM