转载请注明出处:優YoU http://user.qzone.qq.com/289065406/blog/1307201897
题目大意:
给出M个表达式,判断这些信息是否可靠。
解题思路:
差分约束+Bellman-Ford(建议用优化的Bellman-Ford)
设dist[i]为超级源点到i点的距离,则
建立<=的差分系统:
由于P A B X 指“确定A到B的距离(边权)为X”
从P A B X得到的差分系统为
dist[A] - dist[B] >= X && dist[A] - dist[B] <= X
等价于
dist[B] <= dist[A] - X && dist[A] <= dist[B] + X
则if(dist[B] > dist[A]-X) 松弛:dist[B] = dist[A]-X
由于 V A B指“只知道A到B的距离(边权)至少为
从V A B得到的差分系统为
dist[A] >= dist[B] +1
等价于
dist[B] <= dist[A] -1
则if(dist[B] > dist[A] -1) 松弛:dist[B] = dist[A] -1
注意:
(1) 建立<=的差分系统,就必须求最短路(Bellman-Ford算法)。
而信息是否可靠,就是判断图中是否存在负权回路 (也是利用 Bellman-Ford判断)
(2) 由于最坏有10W组不等式,经实测用scanf输入比cin要节省1500ms
(3) 经实测用优化Bellman-Ford算法 比 普通Bellman-Ford算法 快2000ms
1 /*差分约束+优化Bellman*/
2
3 //Memory Time
4 //2596K 485MS
5
6 #include <iostream>
7 using namespace std;
8
9 const int inf=1000000000;
10
11 class
12 {
13 public:
14 int s,e;
15 }edge[200001];
16
17 int N; //太空站数目
18 int M; //tips数
19
20 int dist[1001]; //源点到各点的距离
21 int w[200001]; //边权
22
23 int main(int i,int j)
24 {
25 while(cin>>N>>M)
26 {
27 memset(dist,0,sizeof(dist)); //初始化源点到各点的距离
28 int pe=0;
29
30 for(i=0;i<M;i++)
31 {
32 char pv;
33 int a,b,x;
34
35 getchar(); //吃掉回车
36 scanf("%c",&pv); //由于要频繁输入,用scanf比cin要快1500ms
37
38 if(pv=='P') //清晰边权,即A、B间距离确定,建立双向边
39 {
40 scanf("%d%d%d",&a,&b,&x);
41 edge[pe].s=a;
42 edge[pe].e=b;
43 w[pe++]=x;
44 edge[pe].s=b;
45 edge[pe].e=a;
46 w[pe++]=-x;
47 }
48 else if(pv=='V') //模糊边权,即A、B间距离不确定,建立单向边
49 {
50 scanf("%d%d",&a,&b);
51 edge[pe].s=a;
52 edge[pe].e=b;
53 w[pe++]=1;
54 }
55 }
56
57 /*Bellman-Ford*/
58
59 bool sign; //用于Bellman-Ford算法优化
60 for(j=0;j<N;j++)
61 {
62 sign=false;
63 for(i=0;i<pe;i++)
64 if(dist[ edge[i].e ] > dist[ edge[i].s ] - w[i])
65 {
66 dist[ edge[i].e ] = dist[ edge[i].s ] - w[i];
67 sign=true;
68 }
69 if(!sign)//若dist没有任何改变,则以后也不会改变,可以直接退出循环
70 break;
71 }//循环n次后若flag == false 说明有负权回路,或者权值矛盾
72
73 if(sign)
74 cout<<"Unreliable"<<endl; //存在负权环
75 else
76 cout<<"Reliable"<<endl; //不存在负权环
77
78 }
79 return 0;
80 }
=======华丽的分割线=======
1 /*差分约束+无优化Bellman*/
2
3
4 //Memory Time
5 //2596K 2438MS
6
7 #include<iostream>
8 using namespace std;
9
10 const int inf=1000000000;
11
12 class
13 {
14 public:
15 int s,e;
16 }edge[200001];
17
18 int N; //太空站数目
19 int M; //tips数
20
21 int dist[1001]; //源点到各点的距离
22 int w[200001]; //边权
23
24 int main(int i,int j)
25 {
26 while(cin>>N>>M)
27 {
28 memset(dist,0,sizeof(dist)); //初始化源点到各点的距离
29 int pe=0;
30
31 for(i=0;i<M;i++)
32 {
33 char pv;
34 int a,b,x;
35
36 getchar(); //吃掉回车
37 scanf("%c",&pv);
38 if(pv=='P') //清晰边权,即A、B间距离确定,建立双向边
39 {
40 scanf("%d%d%d",&a,&b,&x);
41 edge[pe].s=a;
42 edge[pe].e=b;
43 w[pe++]=x;
44 edge[pe].s=b;
45 edge[pe].e=a;
46 w[pe++]=-x;
47 }
48 else if(pv=='V') //模糊边权,即A、B间距离不确定,建立单向边
49 {
50 scanf("%d%d",&a,&b);
51 edge[pe].s=a;
52 edge[pe].e=b;
53 w[pe++]=1;
54 }
55 }
56
57 /*Bellman-Ford*/
58
59 /*Relax*/
60
61 for(j=0;j<N;j++)
62 for(i=0;i<pe;i++)
63 if(dist[ edge[i].e ] > dist[ edge[i].s ] - w[i])
64 dist[ edge[i].e ] = dist[ edge[i].s ] - w[i];
65
66 /*Judge the Negative Circle*/
67
68 bool sign=false;
69 for(i=0;i<pe;i++)
70 if(dist[ edge[i].e ] > dist[ edge[i].s ] - w[i])
71 {
72 sign=true;
73 break;
74 }
75
76 if(sign)
77 cout<<"Unreliable"<<endl; //存在负权环
78 else
79 cout<<"Reliable"<<endl; //不存在负权环
80 }
81 return 0;
82 }