Floyed算法 O(N^3)
适用于出现负边权的情况
(a)初始化:点u、v如果有边相连,则dis[u][v]=w[u][v]。
如果不相连,则dis[u][v]=0x7fffffff。
(b)for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(dis[i][j]>dis[i][k]+dis[k][j])
(c)算法结束:dis[i][j]得出的就是从i到j的最短路径
【例题】
Description
平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。
Input
第一行一个整数n。
此后的n行,每行两个整数x和y,描述了一个点的坐标。(第i+1行描述的是第i个点)
第n+2行一个整数m,表示图中连线的个数。
此后的m行,每行描述一条连线,由两个整数i和j组成,表示第i个点和第j个点之间有连线。
最后一行两个整数s和t,分别表示源点和目标点。
Output
仅一行,一个实数(保留两位小数),表示从s到t的最短路径长度。
Sample Input
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5
Sample Output
3.41
【代码】
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
int a[101][3];
double f[101][101];
using namespace std;
int main()
{
int n,m;
int x,y;
int s,t;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i][1]>>a[i][2];
cin>>m;
memset(f,0x7f,sizeof(f));
for(int i=1;i<=m;i++)
{
cin>>x>>y;
f[y][x]=f[x][y]=sqrt(pow(double(a[x][1]-a[y][1]),2)+pow(double(a[x][2]-a[y][2]),2));
}
cin>>s>>t;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if((i!=j)&&(i!=k)&&(j!=k)&&(f[i][k]+f[k][j]<f[i][j]))
f[i][j]=f[i][k]+f[k][j];
printf("%.2lf",f[s][t]);
}
Dijkstra算法 O(n^2)
【基本结构】
int s[maxn];//用来记录某一点是否被访问过
int map[maxn][maxn];//地图
int dis[maxn];//从原点到某一个点的最短距离(一开始是估算距离)
【模板】
int map[N][N];
int dis[N];
int book[N];
int n,target;
int dijkstra(int v)
{
for(int i=1;i<=n;i++)//book数组初始化
{
book[i]=0;
dis[i]=map[v][i];//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
book[1]=1;
}
for(int i=1;i<n;i++)
{
int min=99999999;
int u;
for(int j=1;j<=n;j++)//寻找目前的最短路径的最小点
{
if(book[j]==0&&dis[j]<min)
{
min=dis[j];
u=j;
}
}
book[u]=1;
for(int v=1;v<=n;v++)
{
if(map[u][v]<99999999)
{
if(dis[v]>dis[u]+map[u][v])
{
dis[v]=dis[u]+map[u][v];
}
}
}
}
return dis[target];
}
【题目特征】
给出点的数目、边的数目、起点和终点、边的信息(并且边不包含负边权的值).
求从起点到终点的最短路径的距离
起点:用于dijkstra(int v)中的v
终点:用于return dis[target]中的target
边的信息:用于初始化map[][]
【例题】
Description
有n个站,求从1站到n站的最短路线。
Input
输入第一行n和m, n表示有n个站,m表示有m条道路,(n,m<100)接下来m行每一行输入三个数a,b,d,表示a和b之间有一条长为d 的路。
Output
输出从1到n的最短距离。
Sample Input
5 4
1 2 1
1 5 5
2 4 2
4 5 1
2 1
1 2 3
Sample Output
4
3
【代码】
Floyd算法实现:
#include<iostream>
#include<cstdio>
using namespace std;
int e[101][101];
int n,m;
void initial()
{
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]=99999999;
}
void floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];
}
int main()
{
while((scanf("%d%d",&n,&m))!=EOF)
{
initial();
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
e[a][b]=e[b][a]=c;
}
floyd();
cout<<e[1][n]<<endl;
}
}
Dijkstra算法实现:
#include<iostream>
#include<cstdio>
int map[101][101];
int dis[101];
int book[101];
int n,target;
using namespace std;
int dijkstra(int v)
{
for(int i=1;i<=n;i++)//book数组初始化
{
book[i]=0;
dis[i]=map[v][i];//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
book[1]=1;
}
for(int i=1;i<n;i++)
{
int min=99999999;
int u;
for(int j=1;j<=n;j++)//寻找目前的最短路径的最小点
{
if(book[j]==0&&dis[j]<min)
{
min=dis[j];
u=j;
}
}
book[u]=1;
for(int v=1;v<=n;v++)
{
if(map[u][v]<99999999)
{
if(dis[v]>dis[u]+map[u][v])
{
dis[v]=dis[u]+map[u][v];
}
}
}
}
return dis[target];
}
int main()
{
int m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)//初始化
for(int j=1;j<=n;j++)
if(i==j)
map[i][j]=0;
else
map[i][j]=9999999;
for(int i=1;i<=m;i++)//读入边
{
int a,b,c;
cin>>a>>b>>c;
map[a][b]=map[b][a]=c;
}
target=n;
int ans=dijkstra(1);
cout<<ans<<endl;
}
return 0;
}
Bellman—Ford 算法 O(NE)
算法时间复杂度:O(NE),N是顶点数,E是边数。
能够实现负边权,但无法处理负权回路的情况
【基本结构】
struct Edge
{
int u;
int v;
int weight;
};
Edge edge[101];
int dis[101];//表示原点到i的距离,一开始为估算距离
【模板】
bool bellman_ford()
{
for(int i=1;i<=n;i++)//初始化
dis[i]=99999999;
dis[source]=0;//源节点到自己的距离为0
/********核心语句**********/
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
if(dis[edge[j].v]>dis[edge[j].u]+edge[j].weight)
dis[edge[j].v]=dis[edge[j].u]+edge[j].weight;
if(dis[edge[j].u]>dis[edge[j].v]+edge[j].weight)
dis[edge[j].u]=dis[edge[j].v]+edge[j].weight;
for(int j=1;j<=m;j++)//判断是否有负边权的边
{
if(dis[edge[j].v]>dis[edge[j].u]+edge[j].weight)
return false;
}
return true;
}
【例题代码】
#include<iostream>
#include<cstdio>
using namespace std;
struct Edge
{
int u;
int v;
int weight;
};
Edge edge[101];//用来储存边
int dis[101];//表示原点到i的距离,一开始为估算距离
int source;
int n,m;
bool bellman_ford()
{
for(int i=1;i<=n;i++)//初始化
dis[i]=99999999;
dis[source]=0;//源节点到自己的距离为0
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
{
if(dis[edge[j].v]>dis[edge[j].u]+edge[j].weight)
dis[edge[j].v]=dis[edge[j].u]+edge[j].weight;
if(dis[edge[j].u]>dis[edge[j].v]+edge[j].weight)
dis[edge[j].u]=dis[edge[j].v]+edge[j].weight;
}
for(int j=1;j<=m;j++)//判断是否有负边权的边
{
if(dis[edge[j].v]>dis[edge[j].u]+edge[j].weight)
return false;
}
return true;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=m;i++)
{
cin>>edge[i].u>>edge[i].v>>edge[i].weight;
}
source=1;
bellman_ford();
cout<<dis[n];
}
return 0;
}
SPFA 算法 O(kE)
Bellman-Ford算法的队列实现,减少了不必要的冗余计算。
【模板】
int map[101][101],dist[101];
bool visit[101];
int n,m;
void init()//初始化
{
for(int i=1;i<101;i++)
for(int j=1;j<101;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=map[j][i]=99999999;
}
}
void spfa(int start)
{
queue<int>Q;
int now;
memset(visit,false,sizeof(visit));
for(int i=1;i<=n;i++)
dist[i]=99999999;
dist[start]=0;
Q.push(start);
visit[start]=true;
while(!Q.empty())
{
now=Q.front();
Q.pop();
visit[now]=false;
for(int i=1;i<=n;i++)
{
if(dist[i]>dist[now]+map[now][i])
{
dist[i]=dist[now]+map[now][i];
if(visit[i]==0)
{
Q.push(i);
visit[i]=true;
}
}
}
}
}
}
【例题代码】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int map[101][101],dist[101];
bool visit[101];
int n,m;
void init()
{
for(int i=1;i<101;i++)
for(int j=1;j<101;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=map[j][i]=99999999;
}
}
void spfa(int start)
{
queue<int>Q;
int now;
memset(visit,false,sizeof(visit));
for(int i=1;i<=n;i++)
dist[i]=99999999;
dist[start]=0;
Q.push(start);
visit[start]=true;
while(!Q.empty())
{
now=Q.front();
Q.pop();
visit[now]=false;
for(int i=1;i<=n;i++)
{
if(dist[i]>dist[now]+map[now][i])
{
dist[i]=dist[now]+map[now][i];
if(visit[i]==0)
{
Q.push(i);
visit[i]=true;
}
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(map[a][b] > c)
{
map[a][b]=map[b][a]=c;
}
}
spfa(1);
printf("%d\n",dist[n]);
}
return 0;
}