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

简介

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

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;
}

猜你喜欢

转载自www.cnblogs.com/ubospica/p/9892049.html