次短路

次短路顾名思义,第二短路。

最短路做法:

有两种可能,一是在最短路上重复走最短边,另一个是至少换另一条边到路径里。

正反跑两遍最短路,然后枚举不属于最短路的每条边( \(a\) , \(b\) ) , 找 \(dis[1 \Rightarrow a][0]+val[a][b]+dis[b\Rightarrow n][1]\)

如果 $dis[1 \Rightarrow a][0]+val[a][b]+dis[1\Rightarrow b]= $ 最短路,该边即为最短路上的边,记录最小值最后比较两种可能的最小值。

次短路

const int N=1e6+10;

int n,m,x,y,z,cnt,mn,ans=inf,head[N],dis[N][3],vis[N];
struct node{
	int u,v,w,nxt;
}a[N];

void add(int u,int v,int w){
	a[++cnt]=(node){u,v,w,head[u]};
	head[u]=cnt;
}

priority_queue<int, vector<pair<int,int> > , greater<pair<int,int> > > q;

void dij(int x,int l){
	cl(vis,0);
	dis[x][l]=0;
	q.push(make_pair(0,x));
	while(!q.empty()){
		int now=q.top().se;
		q.pop();
		if(vis[now]) continue;
		vis[now]=1;
		for(int i=head[now];i;i=a[i].nxt){
			int v=a[i].v;
			if(dis[v][l]>dis[now][l]+a[i].w){
				dis[v][l]=dis[now][l]+a[i].w;
				if(!vis[v]){
					q.push(make_pair(dis[v][l],v));
				}
			}
		}
	}
}

signed main(){
	n=read();m=read();
	rep(i,1,m){
		x=read();y=read();z=read();
		if(x==y) continue;
		add(x,y,z);
		add(y,x,z);
	}
	cl(dis,inf);
	dij(1,0);dij(n,1);
	mn=dis[n][0];
	for(int i=1;i<=cnt;i+=2){
		int u=a[i].u,v=a[i].v,w=a[i].w;
		if(dis[u][0]+dis[v][1]>dis[u][1]+dis[v][0]) swap(u,v);
		if(dis[u][0]+dis[v][1]+w==mn) continue;
		ans=Min(ans,dis[u][0]+dis[v][1]+w);
	}
	int mnb=inf;
	for(int i=1;i<=cnt;i+=2){
		int u=a[i].u,v=a[i].v,w=a[i].w;
		if(dis[u][0]+dis[v][1]>dis[u][1]+dis[v][0]) swap(u,v);
		if(dis[u][0]+w+dis[v][1]==mn) mnb=Min(w,mnb);
	}
	cout<<Min(ans,mn+mnb*2);
	return 0;
}

还有一种 \(A\) * 算法(待补)。

posted @ 2023-06-19 19:33  XYini  阅读(6)  评论(0)    收藏  举报