Dijkstra算法
这个算法解决单源最短路问题。
从起点s出发,将与s点相连的点入队,然后更新每一个点的距离。
第二步从入队的点里找一个s到其距离最小的点,然后再以这个点进行拓展更新,如果到达一个点能够将其更新,并且仍未入队,则将这个点入队。
不断地取队里s到其距离最小的点,然后再进行更新。如果更新了的点未入队,则入队。
一直重复到不能够更新位置。
每一次更新,代表会有一个点入队,所以队为空即为全部更新完毕。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
const int oo=2147483647;
int n,m,s;
int pi,p[100005],nex[500005],cost[500005],to[500005];
int val[100005];
bool vis[100005];
struct Dij{
int t,value;
friend bool operator < (Dij i,Dij j)
{
return i.value > j.value;
}
};
priority_queue<Dij> q;
void in_map(int u,int v,int c)
{
pi++; nex[pi]=p[u]; p[u]=pi; cost[pi]=c; to[pi]=v;
}
void read_in()
{
ios::sync_with_stdio(false),cin.tie(0);
cin>>n>>m>>s;
for(int i=1;i<=m;i++)
{
int x,y,c;
cin>>x>>y>>c;
in_map(x,y,c);
}
for(int i=1;i<=n;i++)
val[i]=oo;
}
void Dijkstra()
{
val[s]=0;
Dij S;
S.t=s;
q.push(S);
while(!q.empty())
{
Dij U=q.top();q.pop();
int u=U.t;
if(vis[u]) continue;
vis[u]=true;
for(int k=p[u],v=to[k];k;k=nex[k],v=to[k])
{
if(val[v] > val[u] + cost[k])
{
val[v]=val[u]+cost[k];
Dij V;V.t=v;V.value=val[v];
q.push(V);
}
}
}
for(int i=1;i<=n;i++)
cout<<val[i]<<' ';
}
int main()
{
read_in();
Dijkstra();
return 0;
}
SPFA算法
SPFA算法虽说好用,但是据说会被一些数据卡。
它还是只是解决单源最短路。
先从源点出发,然后将与源点相连的点更新,如果更新的点仍未入队,则入队。
然后按照入队顺序取队里第一个元素,将与之相连的点进行松弛,如果松弛了的点为入队则继续入队。
#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
const int INF=2147483647;
int pi,p[10005],nex[500005],to[500005],cost[500005];
int n,m,s;
int val[10005];
bool vis[10005];
queue<int> q;
void read_into(int u,int v,int c)
{
pi++; nex[pi]=p[u]; p[u]=pi; to[pi]=v; cost[pi]=c;
}
void read_in()
{
ios::sync_with_stdio(false),cin.tie(0);
cin>>n>>m>>s;
for(int i=1;i<=m;i++)
{
int u,v,c;
cin>>u>>v>>c;
read_into(u,v,c);
}
for(int i=1;i<=n;i++)
val[i]=INF;
}
void SPFA()
{
val[s]=0;vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=false;
for(int k=p[u],v=to[k];k;k=nex[k],v=to[k])
{
if(val[v] > val[u] + cost[k])
{
val[v]=val[u]+cost[k];
if(!vis[v])
{
q.push(v);
vis[v]=true;
}
}
}
}
for(int i=1;i<=n;i++)
cout<<val[i]<<' ';
}
int main()
{
read_in();
SPFA();
return 0;
}
Floyd算法
Floyd算法可以解决多源问题,它类似于DP。
假设要找i到j的距离,我们可以找到一个中间点k,用i到k的距离和k到j的距离进行相加得到i到j的距离。
f[i][j]=min(f[i][j],f[i][k]+f[k][j])
利用这个式子来推。
#include<iostream>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
int n,m,s;
int f[10005][10005];
void read_in()
{
ios::sync_with_stdio(false),cin.tie(0);
cin>>n>>m>>s;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=INF;
for(int i=1;i<=m;i++)
{
int u,v,c;
cin>>u>>v>>c;
f[u][v]=min(f[u][v],c);
}
}
void Floyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]=min(f[i][k]+f[k][j],f[i][j]);
}
}
}
f[s][s]=0;
for(int i=1;i<=n;i++)
cout<<f[s][i]<<' ';
}
int main()
{
read_in();
Floyd();
return 0;
}