题目来源
洛谷P2865 [USACO06NOV]路障Roadblocks
https://www.luogu.org/problemnew/show/2865
POJ3255 Roadblocks
http://poj.org/problem?id=3255
思路
将每条无向边拆成两条有向边 建图
分别以1、n为原点SPFA求最短路 分别记为dis1[i]、dis2[i]
枚举每一条有向边i(起点为u 终点为v 长度为w)
经过该有向边i的最短路长即为 dis1[u]+w+dis2[v]
求这些“最短路长”中比“真·最短路”长的最短长度
代码(C++)
#include <cstdio>
#include <queue>
#include <bitset>
#define N 5010
#define M 200010
using namespace std;
bitset<N> in; queue<int> q;
int n,m,u,v,w,cnt=0,pos;
int he[N],fr[M],en[M],ne[M],len[M];
long long ll,dis1[N],dis2[N],minl,ans;
inline void add();
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
scanf("%d%d%d",&u,&v,&w),add();
for(int i=1;i<=n;++i)
dis1[i]=dis2[i]=9223372036854775807;
ans=9223372036854775807;
dis1[1]=0; in[1]=1; q.push(1);
while(!q.empty())
{
pos=q.front(); q.pop(); in[pos]=0;
for(int k=he[pos];k!=0;k=ne[k])
if(dis1[pos]+len[k]<dis1[en[k]])
{
dis1[en[k]]=dis1[pos]+len[k];
if(in[en[k]]==0)
q.push(en[k]),in[en[k]]=1;
}
}
dis2[n]=0; in[n]=1; q.push(n);
while(!q.empty())
{
pos=q.front(); q.pop(); in[pos]=0;
for(int k=he[pos];k!=0;k=ne[k])
if(dis2[pos]+len[k]<dis2[en[k]])
{
dis2[en[k]]=dis2[pos]+len[k];
if(in[en[k]]==0)
q.push(en[k]),in[en[k]]=1;
}
}
minl=dis1[n];
for(int i=1;i<=cnt;++i)
{
ll=dis1[fr[i]]+dis2[en[i]]+len[i];
if(ll>minl&&ll<ans)
ans=ll;
}
printf("%lld",ans);
return 0;
}
inline void add()
{
en[++cnt]=v; len[cnt]=w;
ne[cnt]=he[u]; he[u]=cnt; fr[cnt]=u;
en[++cnt]=u; len[cnt]=w;
ne[cnt]=he[v]; he[v]=cnt; fr[cnt]=v;
}