第六章、最短路径
第一节、只有五行的算法——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 */
添加代码,输出中间矩阵
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 */
第二节、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 */
输出中间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 */
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 */
第三节、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 */
输出中间结果
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 */
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 */
第四节、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 */
oj
以后整理。。。