题目来源
洛谷P3106[USACO14OPEN]GPS的决斗Dueling GPS's
https://daniu.luogu.org/problemnew/show/P3106
思路
1)题目要求判断“边(u,v)”是否“在u到n的最短路径上”,所以
①反向建图 将求u到n的最短路径转化为求n到每个点的最短路径
②记录路径 可转化为记录在最短路条件下i(1<=i<n)是从哪个点走过来的
2)题目中有两个GPS定位系统 分别认定的边权不同 所以一共要做三遍SPFA
①求在第一个GPS系统下每个点到n点的最短路及路径
②求在第二个GPS系统下每个点到n点的最短路及路径
③求答案 由点n走到点1最少受到多少次警告
代码(C++)
#include <cstdio>
#include <queue>
#include <bitset>
#define N 10010
#define M 50010
using namespace std;
bitset<N> in; queue<int> q;
long long dis[N]={0};
int n,m,u,v,w,ww,cnt=0,pos,he[N],f1[N],f2[N];
int en[M],ne[M],l1[M],l2[M],fr[M];
inline void add();
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
scanf("%d%d%d%d",&v,&u,&w,&ww),add();
for(int j=2;j<=n;++j)
dis[j]=9223372036854775807;
in=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(dis[pos]+l1[k]<dis[en[k]])
{
dis[en[k]]=dis[pos]+l1[k];
f1[en[k]]=k;
if(in[en[k]]==0)
q.push(en[k]),in[en[k]]=1;
}
}
for(int i=1;i<n;++i)
dis[i]=9223372036854775807;
in=0; dis[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(dis[pos]+l2[k]<dis[en[k]])
{
dis[en[k]]=dis[pos]+l2[k];
f2[en[k]]=k;
if(in[en[k]]==0)
q.push(en[k]),in[en[k]]=1;
}
}
for(int i=1;i<n;++i)
dis[i]=9223372036854775807;
in=0; dis[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])
{
w=0;
if(k!=f1[en[k]]) ++w;
if(k!=f2[en[k]]) ++w;
if(dis[pos]+w<dis[en[k]])
{
dis[en[k]]=dis[pos]+w;
if(in[en[k]]==0)
q.push(en[k]),in[en[k]]=1;
}
}
}
printf("%lld",dis[1]);
return 0;
}
inline void add()
{
en[++cnt]=v; l1[cnt]=w; l2[cnt]=ww;
ne[cnt]=he[u]; he[u]=cnt; fr[cnt]=u;
}