第一个单源最短路径算法,因为题目可能存在负边,所以用Bellman Ford算法,原始Bellman Ford可以用来求负环,这题需要改进一下用来求正环。
前几次试验一直被图的数据结构所困扰:一开始采用链表,因为BF算法要遍历所有边,而链表对边的遍历占速度优势;后来发现链表操作太繁琐,总共100x100的矩阵,用数组也行,于是想用数组;后来参考了一下大牛们的代码,发现其实用一维数组就能解决问题了。
数据结构:用value[]储存每个点(exchange point)经过exchange操作之后可以转换得到的值,初值统设为0(求负环相应设为正无穷)。rate[][]和com[][]用来储存汇率和回扣。
算法:对原始的Bellman Ford算法进行小改进即可。
另外从discuss中可以知道需要注意精度。
以下是AC代码:Memory:308K,Time:0MS
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
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