zoukankan      html  css  js  c++  java
  • 求解单源最短路问题:Bellman-Ford算法(可判负权回路)详解 之 poj 3268 Silver Cow Party

    /*
    求解单源最短路问题:Bellman-Ford算法(可判负权回路)
    注:
    负权回路: 如果存在一个回路(首尾相同的路径),而且这个回路上所有权值之和是负数,那这就是一个负权回路。
     
    f[i] := 从起点s出发到节点i的最短距离
    故:
    	f[i] = min(f[j] + dis[i][j])
     
    初始值:
    	f[] = INF
    	f[s] = 0;
     
    自己当时遇到的疑惑,以及参考了相关资料获得的解答:
    (1)在实现时,最外侧循环的迭代次数为什么最大是|V|-1次?(|V|节点的个数)
    	答: 前提:在图中不存在负权回路
    		一共有n个节点,求1->n的最短距离,我们知道1->n的最短路径,最多有(n-1)条边。
    		(如果大于(n-1),说明有一个节点在最短路径上走了两次,即走了一个圈,
    			若圈的权为正:显然包含整个圈的路径必定不是最短路径;
    			若圈的权为负:最短路径不存在,因为到达节点的路径距离可以无限变小;
    			若圈的权为0: 去掉之后不影响最优解。
    		)
    		在每次循环中,我们利用f[i] = min(f[j] + dis[i][j])来更新(s->i)的边,每
    		次循环必定会更新成功一条边(更新成功指的是:这条边的权值也是最终最短路径的权值),
    		那么需要(n-1)次循环才可以更新掉所有的边。
    		在《数据结构与编程实验--大学生程序设计课程与竞赛训练教材》(http://book.douban.com/subject/10537877/)上,
    有说到: 很多时候,需要的迭代次数远小于|V|-1,所以可以考虑在每次循环中设置的update的标记, 如果没有update,则说明已获得最优解,跳出循环即可。 时间复杂度:O(V*E) (2)为什么如果f[i]>f[j]+dis[j][i],可以判定有负权回路? 答: 根本原因:求解最短路时 f[i] = min(f[j] + dis[i][j]) 在|V|-1此循环结束,即已获得最优解,如果在图中不存在负权回路,那么必然是f[i]<=f[j]+dis[j][i], 否则必然存在s->i的路径距离比f[i]更短,与已获得最优解矛盾。 代码: for (int i = 0; i < eg.size(); ++i) { if (f[eg[i].egto] > f[eg[i].egfrom] + eg[i].egfrom) { return false; // 出现负权回路 } return true; // 没有出现负权回路 } eg:
    初始:

    边更新后: 3 > 0 + 2 => 出现负权回路
    ------------------------------------------------------- poj 3268 Silver Cow Party what is the longest amount of time a cow must spend walking to the party and back? 故此题需要解决两个问题: (1)所有节点到达节点X的最短距离;
    对于此问题,
    可以反过来想:从X节点到达所有节点的最短距离,答案不变。
    但是此时初始存储的有向边的方向需要调换
    原因:路是单向的,a->b反过来想a<-b,边的方向发生了改变,
    边的权值不变,求解a->b的最短路也就是求a<-b的最短路
    	(2)节点X到达所有节点的最短距离。
    		 按初始存储的有向边进行计算
     
    答案:
    	max{ walkTo[i]+returnTo[i] }
     
    */
     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstdio>
     4 #include <cstddef>
     5 #include <iterator>
     6 #include <algorithm>
     7 #include <string>
     8 #include <locale>
     9 #include <cmath>
    10 #include <vector>
    11 #include <cstring>
    12 #include <map>
    13 #include <utility>
    14 #include <queue>
    15 #include <stack>
    16 #include <set>
    17 using namespace std;
    18 const int INF = 0x3f3f3f3f;
    19 const int MaxN = 205;
    20 const int modPrime = 3046721;
    21 
    22 struct Edge
    23 {
    24     int egfrom, egto, egcost;
    25 };
    26 
    27 int N, M, X;
    28 Edge eg[100010];
    29 int walkTo[1010]; // cow walk to the party 
    30 int returnTo[1010]; // cow return to her farm
    31 
    32 void Solve()
    33 {
    34     bool update = true;
    35     fill(walkTo, walkTo + 1010, INF);
    36     walkTo[X] = 0;
    37     for (int i = 0; i < N && update; ++i)
    38     {
    39         update = false;
    40         for (int j = 0; j < M; ++j)
    41         {
    42             if ((walkTo[eg[j].egto] != INF) && (walkTo[eg[j].egfrom] > walkTo[eg[j].egto] + eg[j].egcost))
    43             {
    44                 walkTo[eg[j].egfrom] = walkTo[eg[j].egto] + eg[j].egcost;
    45                 update = true;
    46             }
    47         }
    48     }
    49 
    50     fill(returnTo, returnTo + 1010, INF);
    51     returnTo[X] = 0;
    52     update = true;
    53     for (int i = 0; i < N && update; ++i)
    54     {
    55         update = false;
    56         for (int j = 0; j < M; ++j)
    57         {
    58             if ((returnTo[eg[j].egfrom] != INF) && (returnTo[eg[j].egto] > returnTo[eg[j].egfrom] + eg[j].egcost))
    59             {
    60                 returnTo[eg[j].egto] = returnTo[eg[j].egfrom] + eg[j].egcost;
    61                 update = true;
    62             }
    63         }
    64     }
    65     
    66     int ans = 0;
    67     for (int i = 1; i <= N; ++i)
    68     {
    69         ans = max(ans, walkTo[i] + returnTo[i]);
    70     }
    71     cout << ans << endl;
    72 }
    73 
    74 int main()
    75 {
    76 #ifdef HOME
    77     freopen("in", "r", stdin);
    78     //freopen("out", "w", stdout);
    79 #endif
    80 
    81     cin >> N >> M >> X;
    82     for (int i = 0; i < M; ++i)
    83     {
    84         cin >> eg[i].egfrom >> eg[i].egto >> eg[i].egcost;
    85     }
    86     Solve();
    87 
    88 
    89 #ifdef HOME
    90     cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
    91     _CrtDumpMemoryLeaks();
    92 #endif
    93     return 0;
    94 }
    
    
    
     
  • 相关阅读:
    CentOS7 设置软件镜像源
    让树莓派自动上报IP地址到邮箱,二代B
    给树莓派安装看门狗的两种方法,二代B
    树莓派(Raspberry Pi)USB无线网卡自动连接,二代B
    升级MAC OX上的Python到3.4
    http 返回码 405 解决方案之一
    CentOS 6.4 SSH 免密码登录
    SVN的Hooks功能--强制添加注释
    PHP开发中,让var_dump调试函数输出更美观 ^_^#
    CentOS 6.4 命令行 安装 VMware Tools
  • 原文地址:https://www.cnblogs.com/shijianming/p/5024831.html
Copyright © 2011-2022 走看看