[模板] 次短路 | bzoj1726-[Usaco2006Nov]Roadblocks第二短路

简介

所谓次短路, 顾名思义, 就是第二短路. 😛

1到n的次短路长度必然产生于:1到x的最短路 + edge(x,y) + y到n的最短路

简单证明一下:

\(dis(i,j)\) 表示 \(i\)\(j\) 的最短路.

假设次短路有两条不在最短路图上的边, 即路径

\[d1: 1 - i - j - k - l - n \]

其中 \(1 - i\), \(j - k\), \(l - n\) 为最短路, \(i - j\), \(k - l\) 为两条边.

我们可以构造出路径

\[d2: 1 - i - j - n \]

其中 \(1 - i\), \(j - n\) 为最短路, \(i - j\) 为一条边.

显然,

\[dis(j,n) < dis(j,k) + e(k,l) + dis(l,n) \]

也就是说, \(d2\) 长度小于 \(d1\);

\[dis(1,n) < dis(1,i) + e(i,j) + dis(j,n) \]

也就是说, \(d2\) 长度大于 \(1\)\(n\) 的最短路.

因此, \(d1\) 不是次短路, 矛盾.

有更多条不在最短路图上的边时同理.

QED.

所以, 用 dij 求一下 \(1\) 点到各点的最短路和 \(n\) 点到各点的最短路, 枚举边即可.

代码见下.

bzoj1726-[Usaco2006Nov]Roadblocks第二短路

板子题.

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;

//--------------------------------------
const int nsz=5050,msz=1e5+50,ninf=1e9+50;
int n,m;

struct te{int t,v,pr;}edge[msz*2];
int hd[nsz],pe=1;
void adde(int f,int t,int v){edge[++pe]=(te){t,v,hd[f]};hd[f]=pe;}
void adddb(int f,int t,int v){adde(f,t,v);adde(t,f,v);}

int dis1[nsz],dis2[nsz];
int vi[nsz];
struct tnd{int t,d;};
bool operator<(tnd l,tnd r){return l.d>r.d;}
void dij(int f,int *dis){
	priority_queue<tnd> pq;
	rep(i,1,n)dis[i]=ninf,vi[i]=0;
	dis[f]=0;
	pq.push((tnd){f,0});
	int u,v,cnt=0;
	while(!pq.empty()){
		u=pq.top().t;pq.pop();
		if(vi[u])continue;
		vi[u]=1;
		for(int i=hd[u];i;i=edge[i].pr){
			v=edge[i].t;
			if(dis[v]>dis[u]+edge[i].v){
				dis[v]=dis[u]+edge[i].v;
				pq.push((tnd){v,dis[v]});
			}
		}
		++cnt;
		if(cnt==n)break;
	}
	rep(i,1,n)cout<<dis[i]<<' ';
	cout<<'\n';
}

int sol(){
	int ans=ninf,tmp;
	dij(1,dis1);
	dij(n,dis2);
	rep(i,2,pe){
		tmp=dis1[edge[i^1].t]+edge[i].v+dis2[edge[i].t];
		if(tmp>dis1[n]&&tmp<ans)ans=tmp;
	}
	return ans;
}

int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	int a,b,c;
	rep(i,1,m){
		cin>>a>>b>>c;
		adddb(a,b,c);
	}
	cout<<sol()<<'\n';
	return 0;
}
posted @ 2018-11-01 19:56  Ubospica  阅读(202)  评论(0编辑  收藏  举报