最短路题型
类型
一.稍微变形的模板
例:1.P1576 最小花费
松弛操作改了一点点。
点击查看代码
if(dis[v]>dis[u]/(1-0.01*w)){
dis[v]=dis[u]/(1-0.01*w);
q.push(make_pair(dis[v],v));
}
2.P3905 道路重建
把好路的边权设置为0。然后跑最短路就行了。
3.P1342 请柬
正反各一遍最短路(好多题都是这个套路,关键是想出来)。
二.最短路径树
这篇博客讲的不错:最短路径树。
还是口胡一下吧。如果讲的哪里有问题,欢迎指出,感谢。
概念
在一张无向边带权图的基础上,构建一棵树,使根节点到树上任意节点的距离都是原图中根节点到该点的最短路。
原理
(即建树原理),一个点到根节点的最短路一定由其他点到根节点的最短路或者直接由根转移过来的。所以一张图就这样构成一棵树了。
操作
与单源最短路模板相比,每个点有一个前继节点,只需在松弛的时候根据题意更换前继节点,就像这样。
点击查看代码
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
pre[v]=u;
q.push(make_pair(dis[v],v));
}else if(dis[v]==dis[u]+w){
if(pre[v]>u) pre[v]=u;
}
例:
1.Paths and Trees
要求边权和最小的最短路径树,即使得该最短路径树的边权和最小。
假设有两条到
可以看出选连接
核心代码:
点击查看代码
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
pre_edge[v]=id;
pre_dis[v]=w;
q.push(make_pair(dis[v],v));
}else if(dis[v]==dis[u]+w&&pre_dis[v]>w){
pre_edge[v]=id;
pre_dis[v]=w;
}
2.P5201 [USACO19JAN]Shortcut G
题意:给定一个有
思路:可以发现,需要将每个节点上的奶牛到根走的路径求出来,然后枚举要在哪个点建立路径。
可以将以
我不会说,核心代码:
点击查看代码
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
pre[v]=u;
q.push(make_pair(dis[v],v));
}else if(dis[v]==dis[u]+w){
if(pre[v]>u) pre[v]=u;//因为要走字典序最小的路径,所以当之前确定的点大于现在可以松弛的点时,说明就得替换前继节点。
}
点击查看代码
for(int i=2;i<=n;i++)
ans=max(ans,1ll*(dis[i]-t)*siz[i]);
剩下一道例题(可以自己去看看):Berland and the Shortest Paths
大概总结一下:其实核心部分还是找前继节点(也就是 else if 那一段),根据题目要求建树就好了。
三.分层图
关于讲解:楠不会(依旧引荐其他大佬的博客)分层图。
例题:1.P4568 [JLOI2011] 飞行路线
可以发现
点击查看代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#define pii pair<long long,int>
using namespace std;
vector<pii> g[200005];
priority_queue<pii,vector<pii>,greater<pii> > q;
int n,m,k,s,t;
bool vis[200005];
long long v[200005];
long long minn=0x7fffffff;
void dij(int s){
v[s]=0;
q.push(make_pair(v[s],s));
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u]){
continue;
}
vis[u]=1;
for(int i=0;i<g[u].size();i++){
int uu=g[u][i].second;
int vv=g[u][i].first;
if(vis[uu]) continue;
if(v[uu]>v[u]+vv){
v[uu]=v[u]+vv;
q.push(make_pair(v[uu],uu));
}
}
}
}
int main(){
cin>>n>>m>>k>>s>>t;
for(int i=0;i<=n*(k+1);i++){
v[i]=0x7fffffff;
}
for(int i=1;i<=m;i++){
int from,to,dis;
cin>>from>>to>>dis;
g[from].push_back(make_pair(dis,to));
g[to].push_back(make_pair(dis,from));
for(int j=1;j<=k;j++){
g[from+j*n].push_back(make_pair(dis,to+j*n));
g[to+j*n].push_back(make_pair(dis,from+j*n));
g[from+(j-1)*n].push_back(make_pair(0,to+j*n));
g[to+(j-1)*n].push_back(make_pair(0,from+j*n));
}
}
dij(s);
for(int i=0;i<=k;i++){
minn=min(minn,v[t+i*n]);
}
cout<<minn;
return 0;
}
三倍经验:
P4822 [BJWC2012]冻结
P2939 [USACO09FEB]Revamping Trails G
四.线段树优化建图
Legacy
题意:一张有向边带权图,三种操作:
操作1
:从
操作2
: 从
操作3
:从
最后求
emm...先鸽了吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效