额,时隔多日,再来复习一下最短路径,顺便整理一下自己的总结:
这里加一个最初版的floyd算法:也就是多源最短路径的一个算法:
#include<stdio.h>
int main()
{
int e[10][10];
int inf=99999999;
int n,m;
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i==j)e[i][j]=0;
else e[i][j]=inf;
}
}
int t1,t2,t3;
for(int i=0; i<m; i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++)
{
if(e[j][k]>e[j][i]+e[i][k]&&e[j][i]<inf&&e[i][k]<inf)e[j][k]=e[j][i]+e[i][k];
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
printf("%d ",e[i][j]);
}
printf("\n");
}
return 0;
}
写这个代码的倒是没什么问题,就是刚开始一直运行不了,然后也没找到错误,其实就是一个小字母打错了,但是花了我半个小时都没找出来,还是我再写一遍代码才发现的,所以,有时候一定要仔细,这里也告诉大家一个找错误的方法,如果你是照着打别人的代码,那你就每打完一行都检查一下,如果不这样的话,一旦你有错误,在这么多没有错误的代码里面找一个小错误,就会产生盲目自信从而找不出那个小错误了。
如果不比较时间复杂度的话,其实优先广度搜索和优先深度搜索都可以求,但是这个时候我已经忘得差不多了,等以后复习完了再来试一下;现在先献上floyd算法,来自啊哈算法:主要是动态规划的思想:大概意思是,要求两个点的路径最短路径,这可以通过中转点来实现,怎么说:
之前,本来想学完单源最短路径就完美结尾然后突然发现好像不行哈哈,写了半天都没过,不是时间超限就是时间超限,就只有简单的学习心得了,没有题目的那种QAQ!!
先上代码(大部分来源于啊哈,算法,现在那本算法书也丢了,还好自己写了这篇总结:
#include<stdio.h>
int main()
{
int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
int inf=99999999;//这里设了一个很大的数,表示正无穷大,这里写题的时候可以根据题目来设置
scanf("%d %d",&n,&m);
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
if(i==j)e[i][j]=0;//这个e的二维数组表示的是位置i到位置j的距离
else e[i][j]=inf;//先对所有数组初始化,自己到自己这里就是0,不能直接到的就为无穷大
for(i=1; i<=m; i++)
{
scanf("%d %d %d",&t1,&t2,&t3);//对输入的单向边进行更新到e数组里面,这里是有向边哦
e[t1][t2]=t3;
}
for(i=1; i<=n; i++)
dis[i]=e[1][i];//把1到每个位置的距离存进一个数组里便于更新,如果直接将表逐个更新会很麻烦,单源最短路径求的是某个点到所有点的最短路径,所以只要所求的就行。
for(i=1; i<=n; i++)
book[i]=0;//先将book数组初始化,这里表示没经过的位置为零
book[1]=1;//这里设初始位置为一所以先将它标记
for(i=1; i<=n-1; i++)//对一这个位置我们要对除一外的位置都要进行尝试,所以是n-1次尝试
{
min=inf;//每次尝试都要初始化
for(j=1; j<=n; j++)
{
if(book[j]==0&&dis[j]<min)//刚开始的时候就是想把这个u去掉,然后结果错了
{//现在想起来不对,好像是到最后j一定为n
min=dis[j];
u=j;//记录最小的值的下标从而进行下面的缩短路径的操作
}
}
book[u]=1;
for(v=1; v<=n; v++)
{
if(e[u][v]<inf)
{
if(dis[v]>dis[u]+e[u][v])//将短的路径和原来的比较,并更新dis数组
dis[v]=dis[u]+e[u][v];
}
}
}
for(i=1; i<=n; i++)
printf("%d ",dis[i]);//打印
getchar();
getchar();
return 0;
}
我也是小白,这时候最好理解的办法就是情景再现,不模拟不知道,一模拟吓一跳,我这里给出我部分模拟的过程,自己模拟之后才会发现很多有趣的东西:
再看一次代码,总结了一下作者的大致思路:先将e的二维数组全都初始化,自己到自己其实是0,而其他地方都现在假设为到不了的地方,假设为无穷大,然后插入相应的要插入的值,表示从哪到哪的路径是多少,其他没有被插入值的地方均为无法到达的,也就还是inf,再把dis数组也初始化,由于我们要求的是单源最短路径,也就是某个点到各个点的最短距离,而这里,我暂时把这个点设为1号点,对了,这时候别忘了去设一个用来标记的数组(这和我们的思路有关,我们想做的是把要求最短路径一步步来求,也就是在每一次刚开始的数组里面,我们都只在寻找一个中转点而不去考虑多个,当求到了经过某个最短路径的点后的这个最短路径时,我们可以再次把这个更小的路径当做是刚开始没有中转点的路径从而去找更多的中转点组成的更短的路径,而这里标记的作用是为了防止一条路径里面有多个一样的点,这是不符合逻辑的,所以为了避免这种情况,才设置的标记)最后就是核心代码了,可以看见在这个核心代码里面,是有一个大循环套了两个小循环,其实看着复杂,懂思路就会显得特别的简单,这里开始的大循环是为了重复完全更新到每一个dis数组里面的点,当然除了该点本身,这时候这个大循环的作用就是计数,循环n-1次就行了,然后小循环1是要找到每一个中转点,最后再在循环2里面找是否输入了可以连接此中转点的后续点,一步步更新,就可以得出最短路径啦。
但是细心的小伙伴们就会发现,其实在大循环里面的第一个小循环里的找最小值可以不用,然后我试了一下,确实是的。但是这是书上的代码,应该是对以后有点用的,先暂时这么写吧
当然,这串代码的小细节也要注意,比如每一个大循环下都要有min的重新初始化等等。
#include<stdio.h>
int main()
{
int n,m;
int e[10][10],book[10],dis[10];
scanf("%d %d",&n,&m);
int inf=999999999;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i==j)e[i][j]=0;
else e[i][j]=inf;
}
}
for(int i=1;i<=n;i++)
{
book[i]=0;
}
book[1]=1;
int a,b,c;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&c);//
e[a][b]=c;
}
for(int i=1;i<=n;i++)
{
dis[i]=e[1][i];
}
int u=0;
for(int i=1;i<=n-1;i++)
{
int minn=inf;
for(int j=1;j<=n;j++)
{
if(book[j]==0&&dis[j]<minn){minn=dis[j];u=j;}
}
book[u]=1;
for(int j=1;j<=n;j++)
{
if(e[u][j]<inf&&dis[u]+e[u][j]<dis[j])dis[j]=dis[u]+e[u][j];//这里判断不对,我们更新的应该是dis数组
}
}
for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
return 0;
}
别说,这是我后来打的代码,还真的不行,我又发现一个致命小错误,首先这种输入是不行的:
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&e[a][b]);//
}
除去变量问题,这个还是无法正常运行QAQ,所以下伙伴们一定要切忌这样用。哦,对了还有一点要格外注意的是,我们在二维数组里面千万不要去更改,改的只是dis数组哦!!!
要知道,你的每一份努力,都会有后面的无限惊喜为你买单,越努力越幸运是真的!!!!