最短路种类 时间复杂度作用局限性
floyd-Warshell O(n^3) 求多源最短路 ,能解决负权边,有向无向图皆可; 时间复杂度太大,不能解决负权环情况;
bellman-ford O(V*E) 求单源最短路,能解决负权边,能解决负权回路并能输出,有向无向图皆可;没有很明显的局限性;
spfa 最坏O(V*E),一般很快求单源最短路,能解决负权边,能解决负权回路不能输出,有向无向图皆可;没有很冥想局限性且一般快于bellman-ford
dijkstra O(n*n)求单源最短路,有向图无向图皆可;不能解决负权边及负权回路;
dijkstra+优先队列优化 (总之非常快,只略逊于对优化) 求单源最短路,有向图无向图皆可;不能解决负权边及负权回路;
下面以hdu2544(超级大水模板题)展示各种算法:
floyd-warshell算法:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100+10;
const int inf = 0x3f3f3f3f;
int gra[maxn][maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2&&n&&m)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) gra[i][j]=0;
else gra[i][j]=inf;//以上4行是初始化;
int a,b,t;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&t);
gra[a][b]=gra[b][a]=t;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(gra[j][k]>gra[j][i]+gra[i][k])
gra[j][k]=gra[j][i]+gra[i][k];//以上5行是floyd-warshell算法核心语句;
printf("%d\n",gra[1][n]);
}
return 0;
}
bellman-ford算法:
如果要判断负环的话加一个cnt数组就行,放置松弛操作的if复合语句里,输出最短路径的话在松弛操作的if复合语句里;
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100+10;
const int inf = 0x3f3f3f3f;//相加也不会超int范围;
int u[20000+10],v[20000+10],w[20000+10];
int dis[maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2&&n&&m)
{
for(int i=1;i<=n;i++) dis[i]=inf;
dis[1]=0;//以上两行是初始化;
int pos=1;
int a,b,t;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&t);
u[pos]=a,v[pos]=b,w[pos]=t;
pos++;
u[pos]=b,v[pos]=a,w[pos]=t;
pos++;
}//因为是无向图;
for(int i=1;i<=n;i++)
for(int j=1;j<pos;j++)
{
if(dis[v[j]]>dis[u[j]]+w[j])
dis[v[j]]=dis[u[j]]+w[j];
}//以上四行是核心语句;
printf("%d\n",dis[n]);
}
return 0;
}
bellman-ford算法+队列优化
邻接表实现:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100+10;
const int inf = 0x3f3f3f3f;
int head[maxn],vis[maxn],dis[maxn];
struct Edge
{
int to,t,next;
};
Edge edge[20000+10];
int pos;
void addedge(int a,int b,int t)
{
edge[pos].next=head[a];
edge[pos].to=b;
edge[pos].t=t;
head[a]=pos++;
}//核心操作;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2&&n&&m)
{
for(int i=1;i<=n;i++)
{
vis[i]=0;
head[i]=-1;
dis[i]=inf;
}
dis[1]=0,pos=0,vis[1]=1;//以上五行初始化;
int a,b,t;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&t);
addedge(a,b,t);
addedge(b,a,t);
}
queue<int>q;
q.push(1);
while(!q.empty())
{
int x=q.front();q.pop();vis[x]=0;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int y=edge[i].to;
int z=edge[i].t;
if(dis[y]>dis[x]+z)
{
dis[y]=dis[x]+z;
q.push(y);
vis[y]=1;//(*);
}
}
}//这个while循环就是核心;
printf("%d\n",dis[n]);
}
return 0;
}
vector实现(之后补充)
dijkstra
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100+10;
int dis[maxn],vis[maxn],gra[maxn][maxn];
int n,m;
int main()
{
while(scanf("%d%d",&n,&m)==2&&n&&m)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) gra[i][j]=0;
else gra[i][j]=inf;
int a,b,t;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&t);
gra[a][b]=gra[b][a]=t;
}
for(int i=1;i<=n;i++)
{
vis[i]=0;
dis[i]=gra[1][i];
}
for(int i=1;i<=n;i++)
{
int maxx=inf,x;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&maxx>=dis[j])
{
maxx=dis[j];
x=j;
}
}
vis[x]=1;
for(int j=1;j<=n;j++)
{
if(dis[j]>dis[x]+gra[x][j])
dis[j]=dis[x]+gra[x][j];
}
}
printf("%d\n",dis[n]);
}
return 0;
}
dijkstra+优先队列优化(邻接表实现)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const int maxn = 100+10;
int head[maxn];
int vis[maxn];
int dis[maxn];
struct Edge
{
int to,t,next;
};
Edge edge[20000+10];
int n,m;
int pos;
void addedge(int a,int b,int t)
{
edge[pos].next=head[a];
edge[pos].to=b;
edge[pos].t=t;
head[a]=pos++;
}
int main()
{
while(scanf("%d%d",&n,&m)==2&&n&&m)
{
for(int i=1;i<=n;i++)
{
head[i]=-1;
vis[i]=0;
dis[i]=inf;
}
pos=0;dis[1]=0;
int a,b,t;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&t);
addedge(a,b,t);
addedge(b,a,t);
}
priority_queue<pii,vector<pii>,greater<pii> > pq;//pair默认先比较第一个元素;
pq.push(pii(0,1));
while(!pq.empty())
{
pii temp=pq.top();pq.pop();
int t1=temp.first;
int t2=temp.second;//后面没有括号,不要混淆;
if(vis[t2]) continue;
vis[t2]=1;
for(int i=head[t2];i!=-1;i=edge[i].next)//i一直都是标号;
{
int z=edge[i].to,zz=edge[i].t;
if(dis[z]>dis[t2]+zz)
{
dis[z]=dis[t2]+zz;
pq.push(pii(dis[z],z));//此处用pq.push(make_pair(dis[z],z))也可;
}
}
}
printf("%d\n",dis[n]);
}
return 0;
}//注意标号从零开始和点从1开始别混淆;
vector实现(有空补充);