最短路,也是单源最短路,能够求出从一个点到达其他所有点的最短距离(n是点,m是边E是不确定)
算法有 Dij(O(n2)很稳定) SPFA(O(nE到nm),据说有很多优化方案,但每种方案又有对应卡你过不去的策略,不建议使用但是据说网络流必须用他) Floyd(O(n3),内部含有dp思想,平时90%不用)Bellman主要判断是否有负环(O(nm)) Dij+堆(O(mlgm)以后解决最短路常用方法,高效又稳定)
其中Dij主要用于正权图,如果有负环需要用SPFA或Bellman
说一下DIJ
数组定义f[x][y]代表 x到y中间有一条路 (因此双向边的时候一定记着把f[y][x]也设置一下)
Vis[x]代表是否走到x
Dis[x]代表当前到达x的最短距离
DIj的过程其实就是一直找连通块外中,且只经过连通块内的点,距离源点(最开始连通块只有起始节点)最近的点,因为这个点一定不能通过其他点来节约距离,所以这个点相当于求出最短路了,由于这个点也加入连通块了,所以要更新DIs(也就是距离当前连通块最近的点)
很多同学不会判-1,有几种方法
- 初始化是INF,最后判断DIs是否是INF即可
- 如果vis【n】没有更改,说明n没走过,也是-1
- 当函数跑到n以后,直接返回dis[n],否则返回-1
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define INF 0x3f3f3f3f
#define MAXN 1005
int f[MAXN][MAXN];
int dist[MAXN],dis[MAXN];
bool vis[MAXN];
int n;
void dijkstra(int x)
{
int i,j;
memset(vis,true,sizeof(vis));
rep(i,1,n)
dist[i]=f[x][i];
vis[x]=false;
int id;
rep(i,1,n-1)
{
id=-1;
rep(j,1,n)
{
if(vis[j]&&(id==-1||dist[j]<dist[id]))
id=j;
}
if(id==-1)
return ;
vis[id]=false;
rep(j,1,n)
{
if(vis[j]&&dist[id]+f[id][j]<dist[j])
dist[j]=dist[id]+f[id][j];
}
}
}
int main()
{
int m;
while(scanf("%d %d",&m,&n)!=EOF)
{
int a,b,v;
memset(f,INF,sizeof(f));
rep(i,1,m)
{
scanf("%d %d %d",&a,&b,&v);
f[a][b]=min(f[a][b],v);
f[b][a]=min(f[b][a],v);
}
dijkstra(1);
printf("%d ",dist[n]);
}
}