写写模板有助于记忆和理解算法。。。
Dijkstra单源最短路算法
非常重要的一个单源最短路算法,适用于边权为正的情况。可以使用堆优化到
O
(
m
l
o
g
n
)
O(mlogn)
O(mlogn)的复杂度,用于处理稀疏图时快的飞起。但对于非常稠密的图时比
O
(
n
2
)
O(n^{2})
O(n2)还要慢。
普通写法
void dijkstra(int s)
{
for(int i=1;i<=n;i++)
{
dis[i]=inf;
done[i]=false;
}
dis[s]=0;
done[s]=true;
int minx=inf,k;
for(int i=1;i<=n;i++)
{
minx=inf;
for(int j=1;j<=n;j++)
{
if(!done[j]&&minx>dis[j])
{
k=j;
minx=dis[j];
}
}
done[k]=true;
for(int j=1;j<=n;j++)
{
if(dis[j]>dis[k]+w[k][j])
dis[j]=dis[k]+w[k][j];
}
}
}
对于最短路用堆优化的问题我习惯于把数据封装到这样一个结构体里
struct edge
{
int from,to,w;
edge(int a,int b,int c):from(a),to(b),w(c){}//构造函数
};
struct dijkstra
{
int n,m;
vector<edge>Edge;
vector<int>g[N];//对边进行编号
int p[N];//记录前驱结点
bool done[N];//标号
int dis[N];//从起点到i的最短距离
void addedge(int from,int to,int w)
{
Edge.push_back(edge(from,to,w));
int num=Edge.size();
g[from].push_back(num-1);
}
};
然后在结构体里写入最短路算法主体
struct heapnode
{
int d,u;
heapnode(int dd,int uu):d(dd),u(uu){}
bool operator<(const heapnode &a)const
{
return d>a.d;
}
};
void dijkstra_q(int s)
{
priority_queue<heapnode>q;//重载运算符为小根堆
q.push(heapnode(0,s));
for(int i=1;i<=n;i++)
{
dis[i]=inf;
done[i]=false;
}
dis[s]=0;
while(!q.empty())
{
heapnode h=q.top();
q.pop();
int u=h.u;
if(done[u]) continue;
done[u]=1;
for(int i=0;i<g[u].size();i++)
{
edge &e=Edge[g[u][i]];
if(dis[e.to]>dis[u]+e.w)
{
dis[e.to]=dis[u]+e.w;
q.push(heapnode(dis[e.to],e.to));
}
}
}
}
需要注意的是需要的内存空间过大,不能开在主函数内。
Bellman-ford算法
可以处理有负权的不含环的最短路,在实践中通常写成队列形式,成为SPFA算法。是其一种队列实现。
void spfa(int s)
{
for(int i=1;i<=n;i++)
{
dis[i]=inf;
done[i]=0;
}
dis[s]=0;
done[s]=1;
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
done[u]=0;
for(int i=0;i<g[u].size();i++)
{
edge &e=Edge[g[u][i]];
if(dis[e.to]>dis[u]+e.w)
{
dis[e.to]=dis[u]+e.w;
if(!done[e.to])
{
q.push(e.to);
done[e.to]=0;
}
}
}
}
}
Floyd算法
最后一个就是仅有五行的Floyd算法了,时间复杂度 O ( n 3 ) O(n^{3}) O(n3)他不是单源的最短路径算法,它可以求出图上所有点之间的最短路径。这也正应征了一句话,复杂度越高的算法越全面。
memset(f,inf,sizeof(f));
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=k&&i!=j&&j!=k)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);