学习心得 - 算法 - 次短路

算一个 ABC 比较常用的工具吧。

(严格)方法 \(1\) Astar + Dij

额这个就是用的 \(k\) 短路改的,\(k=2\)。

这个不用代码。

(严格)方法 \(2\) Dij 维护信息

就是在 Dij 的时候多维护一个次短路然后更新即可。

#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10;
vector<pair<int,int>>e[N];
int n,r,dis[N][2];
struct dij{
	int p,d;
};
bool operator<(dij x,dij y){
	return x.d>y.d;
}
bool vis[N];
priority_queue<dij>q;
signed main(){
	cin>>n>>r;
	for(int i=1;i<=r;i++){
		int u,v,w;
		cin>>u>>v>>w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	memset(dis,0x3f,sizeof(dis));
	dis[1][0]=0;
	q.push({1,0});
	while(q.size()){
		auto f=q.top();
		q.pop();
		vis[f.p]=1;
		for(auto v:e[f.p]){
			if(f.d+v.second<dis[v.first][0]){
				dis[v.first][1]=dis[v.first][0];
				dis[v.first][0]=f.d+v.second;
				q.push({v.first,dis[v.first][0]});
			}
			if(f.d+v.second<dis[v.first][1]
			&&f.d+v.second>dis[v.first][0]){
				dis[v.first][1]=f.d+v.second;
				q.push({v.first,dis[v.first][1]});
			}
		}
	}
	cout<<dis[n][1];
	return 0;
}

(非严格)方法 \(3\) 替换边

从起点 \(s\) 与 \(t\) 各搜一次,然后枚举一条不在原最短路径上的边做替换。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
vector<array<int,3>>e[N];
int n,m,dis[N][2],fir;
pair<int,int>pre[N];
vector<array<int,3>>g;
struct dij{
	int p,d;
};
bool operator<(dij x,dij y){
	return x.d>y.d;
}
bool vis[3*N];
priority_queue<dij>q;
void rep(){
	int p=n;
	while(p){
		vis[pre[p].second]=1;
		p=pre[p].first;
	}
	return;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		e[u].push_back({v,w,i});
		g.push_back({u,v,w});
		e[v].push_back({u,w,i});
	}
	memset(dis,0x3f,sizeof(dis));
	dis[1][0]=0;
	q.push({1,0});
	while(q.size()){
		auto f=q.top();
		q.pop();
		for(auto v:e[f.p])if(f.d+v[1]<dis[v[0]][0]){
			dis[v[0]][0]=f.d+v[1];
			pre[v[0]]={f.p,v[2]};
			q.push({v[0],dis[v[0]][0]});
		}
	}
	if(dis[n][0]==dis[0][0])
		return cout<<-1,0;
	dis[n][1]=0;
	q.push({n,0});
	while(q.size()){
		auto f=q.top();
		q.pop();
		for(auto v:e[f.p])if(f.d+v[1]<dis[v[0]][1]){
			dis[v[0]][1]=f.d+v[1];
			q.push({v[0],dis[v[0]][1]});
		}
	}
	rep();
	int ans=dis[0][0];
	for(int i=1;i<=m;i++)if(!vis[i]){
		int u=g[i-1][0],v=g[i-1][1],w=g[i-1][2];
		ans=min(ans,dis[u][0]+w+dis[v][1]);
		ans=min(ans,dis[v][0]+w+dis[u][1]);
	}
	if(ans==dis[0][0])	
		return cout<<-1,0;
	cout<<dis[n][0]+ans;
	return 0;
}

https://www.luogu.com.cn/article/qskpeqz1

posted @ 2026-10-12 11:44  Ivan422  阅读(2)  评论(0)    收藏  举报