zoukankan      html  css  js  c++  java
  • poj 2983 Is the Information Reliable?

      最短路专题中的一道用到Bellman-Ford算法的题。

      先简单描述题目的意思:

      两个王国将开展一场星级战争,其中一个国家的防御系统被出卖,但是其中的信息有真有假。现在给出某些防御塔间的位置关系,判断是否有矛盾,有矛盾就是不可信,否则就是可信。其中有些是知道具体的相对位置,其余的知知道大概的相对方向,而且各个防御塔都是在南北向的一条直线上。

      根据题意,就可以知道这是要判断是否有矛盾的信息,换句话说就是要判断是否有负权的回路。其中,较为简单而且经典的方法就是Bellman Ford的算法。

      根据《算法导论》描述:

      这个算法能在一般的情况(存在负权边的情况)下,解决单源最短路径问题。对于给定的带权有向图G=(V, E),其源点为s,加权函数为w:E→R,对该图运行Bellman-Ford算法后可以返回一个布尔值,表明图中是否存在一个从源点可达的权为负的回路。若存在这样的回路的话,算法说明该问题无解;若不存在这样的回路,算法将产生最短路径及其权值。

    For i:=1 to |V|-1 do
    For 每条边(u,v)∈E do
      Relax(u,v,w);
    For每条边(u,v)∈E do
      If dis[u]+w<dis[v] Then Exit(False)
    http://www.nocow.cn/index.php?title=Bellman-Ford%E7%AE%97%E6%B3%95&oldid=8177#.E6.94.B9.E8.BF.9B.E5.92.8C.E4.BC.98.E5.8C.96
      这个算法的时间复杂度是O(VE),用于判断是否有负权回路时,它还能稍作优化,我的代码中已实现:
    
    
    View Code
     1 #include<stdio.h>
    2 #include<stdlib.h>
    3 #include<string.h>
    4 #include<math.h>
    5
    6 #define Infp 0x7fffffff
    7 #define Infn 0x80000000
    8 #define DisCon 1000000000
    9 #define MAX 999999999
    10 #define MIN -999999999
    11
    12 #define Z(a) memset(a, 0, sizeof(a))
    13 #define C(a, b) memcpy(a, b, sizeof(b))
    14 #define Pi acos(-1)
    15 #define FMAX (1E300)
    16 #define FMIN (-1E300)
    17 #define feq(a, b) (fabs((a)-(b))<1E-6)
    18 #define flq(a, b) ((a)<(b)||feq(a, b))
    19 #define RG 1005
    20
    21 struct Edge
    22 {
    23 int b;
    24 int e;
    25 int dis;
    26 }e[200010];//简单的记录边的信息
    27
    28 int bell(int en, int pn)
    29 {
    30 int dis[pn+1];
    31 int chg;
    32
    33 dis[0]=0;
    34 for(int i=1; i<=pn; i++)
    35 dis[i]=DisCon;//这是为了防止溢出才不用最大值
    36 for(int i=0; i<pn; i++)
    37 {
    38 chg=0;
    39 for(int j=0; j<en; j++)
    40 if(dis[e[j].e]>dis[e[j].b]+e[j].dis)//松弛操作
    41 {
    42 dis[e[j].e]=dis[e[j].b]+e[j].dis;
    43 chg=1;//如果最终趋于稳定,就是说肯定没有负权回路了
    44 }
    45 if(!chg)return 1;
    46 /*************解释*****************************
    47 结合《算法导论》的解释,如果从单源出发,而且图是无负权回路的,
    48 那么到任何一个短点的最短路径最多只包含|V|-1条边,而上述代码最
    49 外层的循环次数是|V|次,就是最多将构造含有|V|条边的最短路集合。
    50 假设循环不断进行,一直有最短路被发现(也即一直有松弛的路径更新
    51 ),直到i>|V|而退出,这说明这时构造出了一条最短路是有多于|V|条
    52 边的,与初衷矛盾,所以这时说明了图是有负权回路的!
    53 *********************************************/
    54 }
    55 return 0;
    56 }
    57
    58 int main()
    59 {
    60 int N, M;
    61
    62 while(scanf("%d%d", &N, &M)!=EOF)
    63 {
    64 int en=0;
    65 while(M--)
    66 {
    67 getchar();
    68
    69 char c;
    70 scanf("%c", &c);
    71 if(c=='P')//具体的信息,双向的边都要构造
    72 {
    73 int a, b, dis;
    74
    75 scanf("%d%d%d", &a, &b, &dis);
    76 e[en].b=a;
    77 e[en].e=b;
    78 e[en++].dis=dis;
    79 e[en].b=b;
    80 e[en].e=a;
    81 e[en++].dis=-dis;
    82 }
    83 else//模糊的信息,据说边长一定大于1,只构造单向的边
    84 {
    85 int a, b;
    86 scanf("%d%d", &a, &b);
    87 e[en].b=b;
    88 e[en].e=a;
    89 e[en++].dis=-1;
    90 }
    91 }
    92
    93 if(bell(en, N))printf("Reliable\n");
    94 else printf("Unreliable\n");
    95 }
    96
    97 return 0;
    98 }

    UPD:
      看了下差分约束做,结果反而不能1y了。。- -
     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 
     6 using namespace std;
     7 
     8 const int N = 1111;
     9 const int M = 111111;
    10 const int INF = 0x11111111;
    11 struct Edge {
    12     int u, v, c;
    13     Edge() {}
    14     Edge(int u, int v, int c) : u(u), v(v), c(c) {}
    15 } edge[M << 1];
    16 int dis[N];
    17 
    18 bool bellman(int m) {
    19     bool ok;
    20     for (int i = 0; i < N; i++) dis[i] = INF;
    21     for (int i = 0; i < N; i++) {
    22         ok = true;
    23         for (int j = 0; j < m; j++) {
    24             if (dis[edge[j].v] > dis[edge[j].u] + edge[j].c) {
    25                 dis[edge[j].v] = dis[edge[j].u] + edge[j].c;
    26                 ok = false;
    27             }
    28         }
    29         if (ok) return true;
    30     }
    31     return false;
    32 }
    33 
    34 int main() {
    35 //    freopen("in", "r", stdin);
    36     int n, m;
    37     int x, y, c;
    38     char buf[3];
    39     while (~scanf("%d%d", &n, &m)) {
    40         int cnt = 0;
    41         for (int i = 0; i < m; i++) {
    42             scanf("%s%d%d", buf, &x, &y);
    43             if (buf[0] == 'P') {
    44                 scanf("%d", &c);
    45                 edge[cnt++] = Edge(x, y, c);
    46                 edge[cnt++] = Edge(y, x, -c);
    47             } else edge[cnt++] = Edge(y, x, -1);
    48         }
    49         if (bellman(cnt)) puts("Reliable");
    50         else puts("Unreliable");
    51     }
    52     return 0;
    53 }
    View Code
    
    
    

    ——written by Lyon
  • 相关阅读:
    2021-3-11 日报博客
    2021-3-9 日报博客
    2021-3-8 日报博客
    2021-3-7 日报博客
    2021-3-6 周报博客
    2021-3-5 日报博客
    小程序 ----- 条件渲染(if 和 hidden) (七)
    小程序 ---- 简单运算和循环遍历(六)
    小程序 ----- 数据绑定(五)
    .NET ------ Repeater循环嵌套
  • 原文地址:https://www.cnblogs.com/LyonLys/p/poj_2983_Lyon.html
Copyright © 2011-2022 走看看