USACO 2014 US Open Dueling GPS's /// SPFA

题目大意:

给定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
",dis[n]);
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zquzjx/p/10548885.html