如何选择用哪种算法解决最短路径问题??
Floyd | Dijkstra | Bellman-Ford | SPFA | |
---|---|---|---|---|
空间复杂度 | O(N^2) | O(M) | O(M) | O(M) |
时间复杂度 | O(N^3) | O((M+N)logN) | O(NM) | 最坏O(NM) |
适用情况 | 稠密图和顶点关系密切 | 稠密图和顶点关系密切 | 稀疏图和边关系密切 | 稀疏图和边关系密切 |
负权 | 可以解决负权 | 不能解决负权 | 可以解决负权 | 可以解决负权 |
Floyd算法
单向路
算法思想(个人理解):
两个点不能直接到达时会有第三个点在其中作中转,实现两点间接到达
模板
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int inf=0x3f3f3f3f;
int mp[110][110];
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==j)
mp[i][j]=0;
else
mp[i][j]=inf;
}
}
int a,b,t;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&t);
mp[a][b]=t;
}
//核心代码
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(mp[i][j]>mp[i][k]+mp[k][j])
{
mp[i][j]=mp[i][k]+mp[k][j];
}
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
printf("%d ",mp[i][j]);
}
printf("\n");
}
return 0;
}
给一个输入样例:
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
Dijkstra算法
求一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”
算法基本思想:
每次找到离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。
模板
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m;
char a[110];
int mp[110][110];
int inf=0x3f3f3f3f;
int dis[110],book[110];
void init()//初始化
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i==j)
mp[i][j]=0;
else
mp[i][j]=inf;
}
}
}
int main()
{
scanf("%d %d",&n,&m);
init();
int a,b,t;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&t);
mp[a][b]=t;
}
for(int i=1; i<=n; i++)
dis[i]=mp[1][i];//1为起点
book[1]=1;
//Dijkstra算法核心代码
int minn,u;
for(int i=1; i<=n-1; i++)
{
//找到离1号顶点最近的顶点
minn=inf;
for(int j=1; j<=n; j++)
{
if(!book[j]&&dis[j]<minn)
{
minn=dis[j];
u=j;
}
}
book[u]=1;
for(int v=1; v<=n; v++)
{
if(mp[u][v]<inf)
{
if(dis[v]>dis[u]+mp[u][v])
{
dis[v]=dis[u]+mp[u][v];
}
}
}
}
for(int i=1; i<=n; i++)
printf("%d ",dis[i]);
return 0;
}
SPFA算法(BF算法的优化)
题目链接:http://poj.org/problem?id=1511
嗯…用这个题来存一下模板吧
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 1000005
int head[N];
int tot;
long long dis[N];
long long a[N],b[N],s[N];
int vis[N];
int n,m;
int inf=0x3f3f3f3f;
struct node
{
int u,v,w,nx;
} p[N];
void add(int u,int v,int w)//建立邻接表
{
p[tot].u=u;
p[tot].v=v;
p[tot].w=w;
p[tot].nx=head[u];
head[u]=tot++;
}
long long spfa() //SPFA算法模板
{
for(int i=1; i<=n; i++)//初始化
{
vis[i]=0;
dis[i]=inf;
}
queue<int>q;
q.push(1);
vis[1]=1;
dis[1]=0;
while(!q.empty())
{
int u1=q.front();
q.pop();
vis[u1]=0;
for(int i=head[u1]; i!=-1; i=p[i].nx)
{
node e=p[i];
if(dis[e.v]>dis[e.u]+e.w)
{
dis[e.v]=dis[e.u]+e.w;
if(!vis[e.v])
{
vis[e.v]=1;
q.push(e.v);
}
}
}
}
long long sum=0;
for(int i=1; i<=n; i++)
sum+=dis[i];
return sum;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(head,-1,sizeof(head));
tot=0;
scanf("%d %d",&n,&m);
for(int i=1; i<=m; i++)
{
scanf("%d %d %d",&a[i],&b[i],&s[i]);
add(a[i],b[i],s[i]);
}
long long ans=spfa();//计算从1到每个点的最短路径
memset(head,-1,sizeof(head));
tot=0;
for(int i=1; i<=m; i++)
{
add(b[i],a[i],s[i]);
}
long long ans1=spfa();//计算从每个点到1的最短路径
printf("%lld\n",ans+ans1);
}
return 0;
}