最短路模板
1、floyd-warshall
思路
枚举中转站
时间复杂度:\(O(n^3)\)
使用范围:多源点最短路
#include<bits/stdc++.h>
using namespace std;
int e[100][100],k,i,j,n,m,t1,t2,t3;
const int inf=99999;
int main()
{
cin>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)e[i][j]=0;
else e[i][j]=inf;
for(i=1;i<=m;i++)
{
cin>>t1>>t2>>t3;
e[t1][t2]=t3;
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
printf("%ld ",e[i][j]);
}
}
return 0;
}
2、Dijkstra算法
思路:
bfs的思路,从s的邻边开始,选出最短边,再从下一个起点开始,选最短边,期间不停地更新dis,
,此时按照贪心的原理,每次选择离s最短的作为起点,标记后dis不必更新。
使用范围:无负权值的单源点最短路
时间复杂度:\(O(n^2)\)
#include <iostream>
#include <vector>
using namespace std;
struct edge{int to;int cost;};
vector<edge>g[50005];//相当于一个二维数组,存储edge
int d[50005];
int vis[50005];
int n;
const int inf=2147483647;
int djs(int s)
{
int min1,k;
for(int i=1;i<=n;i++) d[i]=inf;
d[s]=0;//初始化
for(int i=1;i<n;i++)
{
min1=inf;k=s;
for(int j=1;j<=n;j++)//寻找离源点最近的且未标记点
if (!vis[j]&&min1>d[j])
{min1=d[j];k=j;}
vis[k]=1;//标记
for(int j=0;j<g[k].size();j++)//重点j从0开始更新未标记的终点to
{
int tm=g[k][j].to;
if(!vis[tm]&& min1+g[k][j].cost<d[tm])
d[tm]=min1+g[k][j].cost;
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
int m,s,x;
cin>>n>>m>>s;//输入点边源
edge tmp;
for(int i=1;i<=m;i++)
{
cin>>x>>tmp.to>>tmp.cost;
g[x].push_back(tmp);//压入g[起点]
}
djs(s);
for(int i=1;i<=n;i++)
cout<<d[i]<<" ";
return 0;
}
堆优化的djs
djs的思路是每次取出dis最小的点,以它为起点更新dis,并且把这个点标记为已知,那么就可以用堆得数据结构降低时间复杂度,取出最小点,并将与之连接的点放入堆中,直至堆空
#include<bits/stdc++.h>
#define re register
using namespace std;
struct edge
{
int to,cost;
};
vector<edge>g[500005];//定义路径结构体
int n,m,s;
int dis[500005];
struct node//定义堆结构体
{
//(如果看不懂)https://www.cnblogs.com/ZERO-/p/9347296.html
int u,d;
bool operator<(const node&rhs)const
{
return d>rhs.d;
}
};
inline void djs()
{
for(re int i=1;i<=n;i++)dis[i]=2147483647;
dis[s]=0;
priority_queue<node>Q;//初始化
node a ={s,0};
Q.push(a);//第一个node
while(!Q.empty())
{
node fr=Q.top();Q.pop();
int u=fr.u,d=fr.d;
//取出并记录
if(d!=dis[u])continue;//避免处理无用数据,也就是dis[u]已经更新,之前未更新数据直接出栈,比如有一组数据 2 5,但是后面又入栈一组数据2 3,则2 5是无用数据
for(re int j=0;j<g[u].size();j++)
{
int tm=g[u][j].to;
if(dis[u]+g[u][j].cost<dis[tm])
{
dis[tm]=dis[u]+g[u][j].cost;
Q.push((node){tm,dis[tm]});
}
}
}
}
int main()
{
cin>>n>>m>>s;
int x;
for (re int i=1;i<=m;i++)
{
edge tmp;
cin>>x>>tmp.to>>tmp.cost;
g[x].push_back(tmp);
}
djs();
for (re int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
3、动态规划
思路
更新更新
#include<bits/stdc++.h>
using namespace std;
long long dis[10100];
int u[500100],v[500100],w[500100],n,m,s,check;//我们定义一个check,优化用
const int inf=2147483647;
int main()
{
cin>>n>>m>>s;//输入
for(int i=1;i<=m;i++)
cin>>u[i]>>v[i]>>w[i];//读入边
for(int i=1;i<=n;i++)
dis[i]=inf;//dis数组初始化
dis[s]=0;
for(int k=1;k<=n-1;k++)
{
check=0;//check归零
for(int i=1;i<=m;i++)
{
if(dis[v[i]]>dis[u[i]]+w[i])
{
dis[v[i]]=dis[u[i]]+w[i];
check=1;//如果dis数值改变,check赋值为1
}
}
if(check==0)
break;//如果没变,直接跳出循环,不要浪费时间
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";//输出
return 0;//好习惯
}
4、SPFA算法
#include<bits/stdc++.h>
const long long inf=2147483647;
const int maxn=10005;
const int maxm=500005;
using namespace std;
int n,m,s,num_edge=0;
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
int next,to,dis;
}edge[maxm]; //结构体表示静态邻接表
void addedge(int from,int to,int dis) //邻接表建图
{ //以下是数据结构书上的标准代码,不懂翻书看解释
edge[++num_edge].next=head[from]; //链式存储下一条出边
edge[num_edge].to=to; //当前节点编号
edge[num_edge].dis=dis; //本条边的距离
head[from]=num_edge; //记录下一次的出边情况
}
void spfa()
{
queue<int> q; //spfa用队列,这里用了STL的标准队列
for(int i=1; i<=n; i++)
{
dis[i]=inf; //带权图初始化
vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
}
q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
while(!q.empty())
{
int u=q.front(); //取出队首
q.pop(); vis[u]=0; //出队标记
for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
{
dis[v]=dis[u]+edge[i].dis;
if(vis[v]==0) //未入队则入队
{
vis[v]=1; //标记入队
q.push(v);
}
}
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1; i<=m; i++)
{
int f,g,w;
cin>>f>>g>>w;
addedge(f,g,w); //建图,有向图连一次边就可以了
}
spfa(); //开始跑spfa
for(int i=1; i<=n; i++)
if(s==i) cout<<0<<" "; //如果是回到自己,直接输出0
else cout<<dis[i]<<" "; //否则打印最短距离
return 0;
} //结束
vector版本的spfa
struct edge
{
int v,w;
};
vector<edge>g[10001];
int d[10001];
int times[10001];
bool vis[10001];
queue<int>q;
int n;
void spfa(int s)
{
memset(vis,0,sizeof(vis));
memset(d,inf,sizeof(d));
memset(times,0,sizeof(times));
while(!q.empty())q.pop();
q.push(s);
vis[s]=1;
d[s]=0;
times[s]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
vis[now]=0;
for(int j=0;j<g[now].size();j++)
{
edge p=g[now][j];
if(d[p.v]>d[now]+p.w)
{
d[p.v]=d[now]+p.w;
times[p.v]++;
debug(times[p.v]);
if(times[p.v]>n)
{
puts("YES");
return;
}
if(!vis[p.v])
{
q.push(p.v);
vis[p.v]=1;;
}
}
}
}
puts("NO");
}
main(void)
{
int t=read(),m;
for(re int i=1;i<=t;i++)
{
n=read();
m=read();
int u,v,w;
for(re int j=1;j<=m;j++)
{
edge t;
u=read(),v=read(),w=read();
t.v=v;
t.w=w;
g[u].push_back(t);
t.v=u;
if(w>=0)g[v].push_back(t);
}
spfa(1);
for(int j=1;j<=n;j++)
g[j].clear();
}
}
参考:题解