题目大意:
给定n个点m条边的有向图
有两个GPS 分别认为 A[i]到B[i] 的一条边的花费是P[i]、Q[i]
当当前走的边不是GPS认为的最短路上的边就会被警告
即两个GPS都不认为是最短路上的边时 会被警告两次
求从点1走到点n被警告次数最少是多少次
https://blog.csdn.net/oakley_/article/details/52510465
按P[i]反向建图 再从n跑最短路到1 然后遍历所有的边判断将不是最短路的边C[i]+1
Q[i]也同样 最后按C[i]从1跑最短路到n 得到的就是被最少警告的次数
为什么要反向建图跑最短路?
因为导航系统到了点2 点3 点4...之后仍然要导航到目标点n
那么就变成了点2到点n的最短路 点3到点n的最短路 ...
所以反向是要使得求出dis[i]为 点i到点n的最短路
若是正向会是 点1到点n的最短路 与要求不符
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define gcd(i,j) __gcd(i,j) #define mem(i,j) memset(i,j,sizeof(i)) #define inc(i,j,k) for(int i=j;i<=k;i++) #define dec(i,j,k) for(int i=j;i>=k;i--) const int N=1e4+5; const int M=1e5+5; int n,m,C[M]; int A[M],B[M],P[M],Q[M]; struct NODE { int to,len,nt; }e[M]; int head[N], tot; void init() { tot=1; mem(head,0); } void addE(int u,int v,int w) { e[tot].to=v; e[tot].len=w; e[tot].nt=head[u]; head[u]=tot++; } int dis[N]; bool inq[N]; void SPFA(int s) { mem(dis,INF); queue<int>q; while(!q.empty()) q.pop(); dis[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=head[u];i;i=e[i].nt) { int v=e[i].to; if(dis[v]<=dis[u]+e[i].len) continue; dis[v]=dis[u]+e[i].len; if(!inq[v]) inq[v]=1, q.push(v); } } } void check(int u[],int v[],int w[],int st) { init(); inc(i,1,m) addE(u[i],v[i],w[i]); SPFA(st); inc(i,1,m) if(dis[v[i]]!=dis[u[i]]+w[i]) C[i]++; } int main() { while(~scanf("%d%d",&n,&m)) { inc(i,1,m) scanf("%d%d%d%d",&A[i],&B[i],&P[i],&Q[i]); mem(C,0); check(B,A,P,n); check(B,A,Q,n); check(A,B,C,1); printf("%d\n",dis[n]); } return 0; }
USACO 2014 US Open Dueling GPS's /// SPFA
原文地址:https://www.cnblogs.com/zquzjx/p/10548885.html
时间: 2024-10-29 04:23:53