最短路
输入保证至少存在1条商店到赛场的路线。
2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
3 2
无向图.....
最简单的最短路
dijkstra 算法:
这个算法最适合的是求单源最短路,也就是单个起点的最短路径,要求路径没有负值,
实现方法是从起点入手,每一次都找到距离起点最近(边最短)的那个点,然后把对应的距离记录下来,然后把这个点和刚才的起点放在同一个集合(也就是相当于已经连接过了),然后再找一个距离这两个点最近的一个点,把这个点也放入刚才那个点的集合中,对应的长度也记录下来,每一步都这样下去,注意关键的一步:
每次加入某个点之后,可能引起起点到另外一个点的距离变短,那么就要进行距离更新了,这个过程在这个算法里叫“松弛”操作,其实就是很理所应当的做法: 如果1-x距离加上x-y的长度为10,有一条直接1-y的距离为5,肯定保留的是1-y 这条路的长度,也就是之前的dis[y]=10,更新dis[y]=5;实现这个操作就是利用循环,每次加入一个元素的时候都检验一遍是不是所有的路径都是当前最优的方法,如果不是,就更新成最优,每一次都这样下去,最终dis数组里面保存的值都是从起点到其他各个点的最短路径,但是可能有某些点根本就无法到达,也就是可能就不相互连通,所以为了解决这个问题,提前需要处理的一下dis数组,把里面的值全部赋值为inf(自己定义一个足够大的值),相当于无穷大,也就是没路相连的时候。在加入边(路)的时候,把这个值更新为相应的值就行了,这样下来,不但能记录最短路径也不会影响其他的不连通的元素的状态
最终状态是,dis 数组,里面保存的值,就是起点到这个点的最短路径的长度,比如dis[5]=10,就是从起点到第五号顶点的最短距离是10,而起点到起点的距离为0。
虽然这个算法很好用,但是不能计算带负权值的最短路,因为算法执行期间,每次更新完全一个顶点对应的距离之后,下次不会再次遍历这个顶点(标记数组标记)也就不会再次更新这个距离,所以有负权值的图也就计算不出最短路径了。具体解决可以使用spfa算法,这个算法可以解决带负权值的最短路,这里不在赘述。个人理解的可能有纰漏,有错误的地方还望大神指点
.
#include<stdio.h>
#include<string.h>
#define min(a,b) (a>b?b:a)
#define inf 0x3f3f3f3f
int used[105],d[105],cost[105][105],n,m;
void dijkstra(int s)
{
for(int i=1;i<=n;++i)
{
d[i]=inf;
used[i]=0;
}
d[s]=0;//used[s]=1;
while(1)
{
int v=-1;
for(int u=1;u<=n;++u)
{
if(!used[u]&&(v==-1||d[u]<d[v]))
{
v=u;
}
}
if(v==-1)
{
break;
}
used[v]=1;
for(int u=1;u<=n;++u)
{
d[u]=min(d[u],d[v]+cost[v][u]);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m),m|n)
{
memset(cost,inf,sizeof(cost));
memset(used,inf,sizeof(used));
for(int i=0;i<m;++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
cost[a][b]=cost[b][a]=min(cost[a][b],c);
}
dijkstra(1);
printf("%d\n",d[n]);
}
return 0;
}