第一个单源最短路径算法,因为题目可能存在负边,所以用Bellman Ford算法,原始Bellman Ford可以用来求负环,这题需要改进一下用来求正环。
前几次试验一直被图的数据结构所困扰:一开始采用链表,因为BF算法要遍历所有边,而链表对边的遍历占速度优势;后来发现链表操作太繁琐,总共100x100的矩阵,用数组也行,于是想用数组;后来参考了一下大牛们的代码,发现其实用一维数组就能解决问题了。
数据结构:用value[]储存每个点(exchange point)经过exchange操作之后可以转换得到的值,初值统设为0(求负环相应设为正无穷)。rate[][]和com[][]用来储存汇率和回扣。
算法:对原始的Bellman Ford算法进行小改进即可。
另外从discuss中可以知道需要注意精度。
以下是AC代码:Memory:308K,Time:0MS
![]()
![]() Code
Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #define MAX 101
 4 #define eps 1e-8
 5 int N, M, S;
 6 double value[MAX];
 7 double rate[MAX][MAX];
 8 double com[MAX][MAX];
 9 
10 int Bellman_Ford()
11 {
12     int i, j, k, relaxed;
13     for (k=0;k<N-1;k++){//N-1 passes
14         relaxed=0;
15         for (i=1;i<=N;i++){
16             for (j=1;j<=N;j++){
17                 if (i!=j && rate[i][j]>eps && value[j]+eps<(value[i]-com[i][j])*rate[i][j]){
18                     //RELAX
19                     value[j]=(value[i]-com[i][j])*rate[i][j];
20                     relaxed=1;
21                 }
22             }
23         }
24         //如果没有松弛操作,即不存在正环
25         if (!relaxed){
26             return 0;
27         }
28     }
29     //查找正环
30     for (i=1;i<=N;i++){
31         for (j=1;j<=N;j++){
32             if (i!=j && rate[i][j]>eps && value[j]+eps<(value[i]-com[i][j])*rate[i][j]){
33                 return 1;        
34             }
35         }
36     }
37     return 0;
38 }
39 int main()
40 {
41     int a, b, i;
42     double Rab, Cab, Rba, Cba, v;
43     //freopen("input.txt", "r", stdin);
44     while (scanf("%d %d %d %lf", &N, &M, &S, &v)!=EOF){
45         value[S]=v;
46         for (i=0;i<M;i++){
47             scanf("%d %d %lf %lf %lf %lf", &a, &b, &Rab, &Cab, &Rba, &Cba);
48             rate[a][b]=Rab;
49             rate[b][a]=Rba;
50             com[a][b]=Cab;
51             com[b][a]=Cba;
52         }
53         if (Bellman_Ford()){
54             printf("YES\n");
55         }
56         else{
57             printf("NO\n");
58         }
59     }
60     return 0;
61 }
END