欣乐

The eagles are coming!

导航

第六章、最短路径

第一节、只有五行的算法——Floyd-Warshall(多源最短路径)
p152 FW算法完整代码

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int e[10][10],k,i,j,n,m,t1,t2,t3;
 5     int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
 6     //读入n和m,n表示顶点个数,m表示边的条数
 7     scanf("%d %d",&n,&m);
 8     
 9     //初始化
10     for(i=1;i<=n;i++)
11         for(j=1;j<=n;j++)
12             if(i==j) e[i][j]=0;  
13                 else e[i][j]=inf;
14 
15     //读入边
16     for(i=1;i<=m;i++)
17     {
18         scanf("%d %d %d",&t1,&t2,&t3);
19         e[t1][t2]=t3;
20     }
21     
22     //Floyd-Warshall算法核心语句
23     for(k=1;k<=n;k++)
24         for(i=1;i<=n;i++)
25             for(j=1;j<=n;j++)
26                 //if(e[i][j]>e[i][k]+e[k][j] ) 
27                 if(e[i][k]<inf && e[k][j]<inf && e[i][j]>e[i][k]+e[k][j])                  
28                     e[i][j]=e[i][k]+e[k][j];
29     
30     //输出最终的结果
31     for(i=1;i<=n;i++)
32     {
33          for(j=1;j<=n;j++)
34         {
35              printf("%10d",e[i][j]);
36         }
37         printf("\n");
38     }
39     
40     return 0;
41 }
42 
43 /*
44 
45 4 8
46 1 2 2
47 1 3 6
48 1 4 4
49 2 3 3
50 3 1 7
51 3 4 1
52 4 1 5
53 4 3 12
54 
55 4 9
56 1 2 2
57 1 3 6
58 1 4 4
59 2 3 3
60 3 1 7
61 3 4 1
62 4 1 5
63 4 2 1
64 4 3 12
65 
66 为测试经过任意数点,加测试数据一组
67 */
View Code


添加代码,输出中间矩阵

 1 #include <stdio.h>
 2 int e[10][10],k,i,j,n,m,t1,t2,t3;
 3 
 4 void printm()
 5 {
 6     int i,j;
 7     for(i=1;i<=n;i++)
 8     {
 9          for(j=1;j<=n;j++)
10         {
11              printf("%5d",e[i][j]);
12         }
13         printf("\n");
14     }
15     printf("\n");  
16 }
17 
18 int main()
19 {
20     int inf=999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
21     //读入n和m,n表示顶点个数,m表示边的条数
22     scanf("%d %d",&n,&m);
23     
24     //初始化
25     for(i=1;i<=n;i++)
26         for(j=1;j<=n;j++)
27             if(i==j) e[i][j]=0;  
28                 else e[i][j]=inf;
29 
30     //读入边
31     for(i=1;i<=m;i++)
32     {
33         scanf("%d %d %d",&t1,&t2,&t3);
34         e[t1][t2]=t3;
35     }
36     printf("\n");
37     printm();
38     
39     //Floyd-Warshall算法核心语句
40     for(k=1;k<=n;k++)
41     {
42         for(i=1;i<=n;i++)
43             for(j=1;j<=n;j++)
44                 //if(e[i][j]>e[i][k]+e[k][j] ) 
45                 if(e[i][k]<inf && e[k][j]<inf && e[i][j]>e[i][k]+e[k][j])                  
46                     e[i][j]=e[i][k]+e[k][j];
47         printm();
48     }
49    
50     return 0;
51 }
52   
53 /*
54 
55 4 8
56 1 2 2
57 1 3 6
58 1 4 4
59 2 3 3
60 3 1 7
61 3 4 1
62 4 1 5
63 4 3 12
64 
65 */
View Code

 


第二节、Dijkstra算法——通过边实现松弛(单源最短路径)
p158 Ds算法完整代码

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
 5     int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
 6     //读入n和m,n表示顶点个数,m表示边的条数
 7     scanf("%d %d",&n,&m);
 8     
 9     //初始化
10     for(i=1;i<=n;i++)
11         for(j=1;j<=n;j++)
12             if(i==j) e[i][j]=0;  
13               else e[i][j]=inf;
14               
15     //读入边
16     for(i=1;i<=m;i++)
17     {
18         scanf("%d %d %d",&t1,&t2,&t3);
19         e[t1][t2]=t3;
20     }
21 
22     //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
23     for(i=1;i<=n;i++)
24         dis[i]=e[1][i];
25 
26     //book数组初始化
27     for(i=1;i<=n;i++)
28         book[i]=0;
29     book[1]=1;
30     
31     //Dijkstra算法核心语句
32     for(i=1;i<=n-1;i++)
33     {
34         //找到离1号顶点最近的顶点
35         min=inf;
36         for(j=1;j<=n;j++)
37         {
38             if(book[j]==0 && dis[j]<min) //在集合Q中找到最近的顶点
39             {
40                 min=dis[j];
41                 u=j; //记录下顶点位置
42             }
43         }
44         book[u]=1; //顶点u加入集合P
45         for(v=1;v<=n;v++)
46         {
47             if(e[u][v]<inf) //对每个出边指向点
48             {
49                 if(dis[v]>dis[u]+e[u][v]) 
50                     dis[v]=dis[u]+e[u][v]; //松弛
51             }
52         }    
53     }
54     
55     //输出最终的结果
56     for(i=1;i<=n;i++)
57         printf("%d ",dis[i]);
58         
59     getchar();
60     getchar();
61     return 0;
62 }
63 
64 /*
65 
66 6 9
67 1 2 1
68 1 3 12
69 2 3 9
70 2 4 3
71 3 5 5
72 4 3 4
73 4 5 13
74 4 6 15
75 5 6 4
76 
77 */
View Code


输出中间dis数组

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
 5     int inf=999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
 6     //读入n和m,n表示顶点个数,m表示边的条数
 7     scanf("%d %d",&n,&m);
 8     
 9     //初始化
10     for(i=1;i<=n;i++)
11         for(j=1;j<=n;j++)
12             if(i==j) e[i][j]=0;  
13               else e[i][j]=inf;
14               
15     //读入边
16     for(i=1;i<=m;i++)
17     {
18         scanf("%d %d %d",&t1,&t2,&t3);
19         e[t1][t2]=t3;
20     }
21 
22     //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
23     for(i=1;i<=n;i++)
24         dis[i]=e[1][i];
25 
26     //book数组初始化
27     for(i=1;i<=n;i++)
28         book[i]=0;
29     book[1]=1;
30 
31         for(j=1;j<=n;j++)
32             printf("%5d",dis[j]);
33         printf("\n"); //
34     
35     //Dijkstra算法核心语句
36     for(i=1;i<=n-1;i++)
37     {
38         //找到离1号顶点最近的顶点
39         min=inf;
40         for(j=1;j<=n;j++)
41         {
42             if(book[j]==0 && dis[j]<min) //在集合Q中找到最近的顶点
43             {
44                 min=dis[j];
45                 u=j; //记录下顶点位置
46             }
47         }
48         book[u]=1; //顶点u加入集合P
49         for(v=1;v<=n;v++)
50         {
51             if(e[u][v]<inf) //对每个出边指向点
52             {
53                 if(dis[v]>dis[u]+e[u][v]) 
54                     dis[v]=dis[u]+e[u][v]; //松弛
55             }
56         }
57         for(j=1;j<=n;j++)
58             printf("%5d",dis[j]);
59         printf("\n"); //
60     }
61        
62     getchar(); getchar();
63     return 0;
64 }
65 
66 /*
67 
68 6 9
69 1 2 1
70 1 3 12
71 2 3 9
72 2 4 3
73 3 5 5
74 4 3 4
75 4 5 13
76 4 6 15
77 5 6 4
78 
79 */
View Code


p160 邻接表的数组方法(不用链表)
以下这个博客中的内容,比书中说得更清楚:
http://www.cnblogs.com/ahalei/p/3651334.html
代码:

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int n,m,i,k;
 5     //u、v和w的数组大小要根据实际情况来设置,要比m的最大值要大1
 6     int u[60],v[60],w[60];
 7     //first和next的数组大小要根据实际情况来设置,要比n的最大值要大1
 8     int first[50],next[50];
 9     scanf("%d %d",&n,&m);
10     //初始化first数组下标1~n的值为-1,表示1~n顶点暂时都没有边
11     for(i=1;i<=n;i++)
12         first[i]=-1;
13     for(i=1;i<=m;i++)
14     {
15         scanf("%d %d %d",&u[i],&v[i],&w[i]);//读入每一条边
16         //下面两句是关键啦
17         next[i]=first[u[i]];
18         first[u[i]]=i;
19     }
20 
21     for(i=1;i<=n;i++)
22     {
23         k=first[i];
24         while(k!=-1)
25         {
26             printf("%d is : %d %d %d\n",i,u[k],v[k],w[k]);
27             k=next[k];
28         }
29         printf("\n");
30     }  
31 
32     getchar();  getchar();
33     return 0;
34 }
35 
36 /*
37 
38 4 5
39 1 4 9
40 4 3 8
41 1 2 5
42 2 4 6
43 1 3 7
44 
45 p155 的图,第二组测试数据
46 
47 6 9
48 1 2 1
49 1 3 12
50 2 3 9
51 2 4 3
52 3 5 5
53 4 3 4
54 4 5 13
55 4 6 15
56 5 6 4
57 
58 */
View Code

 


第三节、Bellman-Ford算法——解决负权边
p168 BF算法完整代码

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int dis[10],i,k,n,m,u[10],v[10],w[10];
 5     int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
 6     //读入n和m,n表示顶点个数,m表示边的条数
 7     scanf("%d %d",&n,&m);
 8   
 9     //读入边
10     for(i=1;i<=m;i++)
11         scanf("%d %d %d",&u[i],&v[i],&w[i]);
12 
13     //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
14     for(i=1;i<=n;i++)
15         dis[i]=inf;
16     dis[1]=0;
17 
18     //Bellman-Ford算法核心语句
19     for(k=1;k<=n-1;k++)
20       for(i=1;i<=m;i++)
21         if( dis[v[i]] > dis[u[i]] + w[i] )
22           dis[v[i]] = dis[u[i]] + w[i];
23 
24     //输出最终的结果
25     for(i=1;i<=n;i++)
26         printf("%d ",dis[i]);
27         
28     getchar();
29     getchar();
30     return 0;
31 }
32 
33 /*
34 
35 5 5
36 2 3 2
37 1 2 -3
38 1 5 5
39 4 5 2
40 3 4 3
41 
42 */
View Code


输出中间结果

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int dis[10],i,k,n,m,u[10],v[10],w[10];
 5     int inf=999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
 6     //读入n和m,n表示顶点个数,m表示边的条数
 7     scanf("%d %d",&n,&m);
 8   
 9     //读入边
10     for(i=1;i<=m;i++)
11         scanf("%d %d %d",&u[i],&v[i],&w[i]);
12 
13     //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
14     for(i=1;i<=n;i++)
15         dis[i]=inf;
16     dis[1]=0;
17 
18     //Bellman-Ford算法核心语句
19     for(k=1;k<=n-1;k++)
20     {
21       for(i=1;i<=m;i++)
22         if( dis[v[i]] > dis[u[i]] + w[i] )
23           dis[v[i]] = dis[u[i]] + w[i];
24       //输出中间结果
25       for(i=1;i<=n;i++)
26           printf("%5d",dis[i]);
27       printf("\n");
28     }
29         
30     getchar(); getchar();
31     return 0;
32 }
33 
34 /*
35 
36 5 5
37 2 3 2
38 1 2 -3
39 1 5 5
40 4 5 2
41 3 4 3
42 
43 测试p155的图
44 
45 6 9
46 1 2 1
47 1 3 12
48 2 3 9
49 2 4 3
50 4 3 4
51 3 5 5
52 4 5 13
53 4 6 15
54 5 6 4
55 
56 与读入边的顺序,很有关系:
57 
58 6 9
59 4 6 15
60 5 6 4
61 2 4 3
62 4 3 4
63 3 5 5
64 4 5 13
65 1 2 1
66 1 3 12
67 2 3 9
68 
69 */
View Code


p170 BF算法改进代码,可判断是否含有负权回路

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int dis[10],i,k,n,m,u[10],v[10],w[10];
 5     int bak[10],check,flag; //
 6     int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
 7     //读入n和m,n表示顶点个数,m表示边的条数
 8     scanf("%d %d",&n,&m);
 9   
10     //读入边
11     for(i=1;i<=m;i++)
12         scanf("%d %d %d",&u[i],&v[i],&w[i]);
13 
14     //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
15     for(i=1;i<=n;i++)
16         dis[i]=inf;
17     dis[1]=0;
18 
19     //Bellman-Ford算法核心语句
20     for(k=1;k<=n-1;k++)
21     {
22       //备份
23       for(i=1;i<=n;i++) bak[i]=dis[i];
24       //松弛
25       for(i=1;i<=m;i++)
26         if( dis[v[i]] > dis[u[i]] + w[i] )
27           dis[v[i]] = dis[u[i]] + w[i];
28       //检测dis数组是否有更新
29       check=0;
30       for(i=1;i<=n;i++)
31         if(bak[i]!=dis[i]) 
32         {
33           check=1;
34           break;
35         }
36       if(check==0) break; //如无更新,跳出循环
37     }
38     //检测负权回路
39     flag=0;
40     for(i=1;i<=m;i++)
41       if(dis[v[i]] > dis[u[i]]+w[i]) flag=1;
42         
43     if(flag==1) printf("have fqhl");
44     else
45     {
46       //输出最终的结果
47       for(i=1;i<=n;i++)
48         printf("%d ",dis[i]);
49     }    
50     getchar();  getchar();
51     return 0;
52 }
53 
54 /*
55 
56 5 6
57 2 3 2
58 1 2 -3
59 1 5 5
60 4 5 2
61 3 4 3
62 4 3 -8
63 
64 */
View Code

 


第四节、BF算法的队列优化
p174 BF算法的队列优化代码

 1 #include <stdio.h>
 2 int main()
 3 {
 4   int n,m,i,k;
 5   int u[8],v[8],w[8];
 6   int first[6],next[8];
 7   int dis[6]={0},book[6]={0};
 8   int que[101]={0},head=1,tail=1;
 9   int inf=99999999;
10   
11   //读入n和m,n表示顶点个数,m表示边的条数
12   scanf("%d %d",&n,&m);
13   
14   //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
15   for(i=1;i<=n;i++)
16     dis[i]=inf;
17   dis[1]=0;  
18   
19   for(i=1;i<=n;i++) book[i]=0;
20     
21   for(i=1;i<=n;i++) first[i]=-1;
22   
23   //读入边
24   for(i=1;i<=m;i++)
25   {
26     scanf("%d %d %d",&u[i],&v[i],&w[i]);
27     //
28     next[i]=first[u[i]];
29     first[u[i]]=i;
30   }
31 
32   que[tail]=1; tail++;
33   book[1]=1;
34   
35   while(head<tail)
36   {
37     k=first[que[head]];
38     while(k!=-1)
39     {
40       if( dis[v[k]] > dis[u[k]] + w[k] )
41       {
42         dis[v[k]] = dis[u[k]] + w[k];
43         //
44         if(book[v[k]]==0)
45         {
46           que[tail]=v[k];
47           tail++;
48           book[v[k]]=1;
49         }
50       }
51       k=next[k];
52     }
53     book[que[head]]=0;
54     head++;
55   }
56   
57   //输出最终的结果
58   for(i=1;i<=n;i++)
59     printf("%d ",dis[i]);
60   getchar();  getchar();
61   return 0;
62 }
63 
64 /*
65 
66 5 7
67 1 2 2
68 1 5 10
69 2 3 3
70 2 5 7
71 3 4 4
72 4 5 5
73 5 3 6
74 
75 */
View Code

 





oj
以后整理。。。

 

 




top

posted on 2014-10-21 13:25  欣乐  阅读(161)  评论(0编辑  收藏  举报