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
原文地址:https://www.cnblogs.com/LyonLys/p/poj_2983_Lyon.html