USACO2014 Open Silver Dueling GPSs


Description

Farmer John has recently purchased a new car online, but in his haste he accidentally clicked the “Submit” button twice when selecting extra features for the car, and as a result the car ended up equipped with two GPS navigation systems! Even worse, the two systems often make conflicting decisions about the route that FJ should take.

The map of the region in which FJ lives consists of N intersections(2 N 10,000) and M directional roads (1 M 50,000). Road i connects intersections Ai(1 Ai N ) and Bi(1 Bi N ).Multiple roads could connect the same pair of intersections, and a bi-directional road (one permitting two-way travel) is represented by two separate directional roads in opposite orientations. FJ’s house is located at intersection 1, and his farm is located at intersection N. It is possible to reach the farm from his house by traveling along a series of directional roads.

Both GPS units are using the same underlying map as described above; however, they have different notions for the travel time along each road. Road i takes Pi units of time to traverse according to the first GPS unit, and Qi units of time to traverse according to the second unit (each
travel time is an integer in the range [1,105] ).

FJ wants to travel from his house to the farm. However, each GPS unit complains loudly any time FJ follows a road (say, from intersection X to intersection Y) that the GPS unit believes not to be part of a shortest route from X to the farm (it is even possible that both GPS units can complain, if FJ takes a road that neither unit likes).

Please help FJ determine the minimum possible number of total complaints he can receive if he chooses his route appropriately. If both GPS units complain when FJ follows a road, this counts as +2 towards the total.

题目大意

给定含有N个结点,M条边的有向图,每条边分别有两个权值表示GPS1和GPS2的估价距离。求出最少有多少次,FJ会违背GPS所指定的下一条最优路线。如果FJ本次选择的路线与两个GPS都不相同,则次数+2。

Input

Line 1: The integers N and M.
Line i describes road i with four integers: Ai , Bi , Pi , Qi .

Sample Input

5 7
3 4 7 1
1 3 2 20
1 4 17 18
4 5 25 3
1 2 10 1
3 5 4 14
2 4 6 5

Output

Line 1: The minimum total number of complaints FJ can receive if he routes himself from his house to the farm optimally.

Sample Output

1

Output Details

If FJ follows the path 1 -> 2 -> 4 -> 5, then the first GPS complains on the 1 -> 2 road (it would prefer the 1 -> 3 road instead). However, for the rest of the route 2 -> 4 -> 5, both GPSs are happy, since this is a shortest route from 2 to 5 according to each GPS.
大意:走1->2->4->5这条路线,只会有一次违背。


Solution
注意给出的图是有向图,因为这个被坑了好久……

考虑GPS的工作方式:它给出的是当前的点到终点的最短距离路径,而与之前经过的路径无关。如果离开了原先设定的最短路,它会重新以该点为起点找一条最短路(甚至回跑到原先经过的点)。即到了一个点就找一次最短路。但如果正着找一遍这个点到所有点的最短路,就有很多不必要的点被更新了。

那么我们只需要根据两种权值各自跑一遍从终点n开始的Dijkstra,得到每个点到终点的最短路径。之后再判断某条边是否在某段最短路径上,如果不是,接下来选这条边总违反次数就会增加。

那么根据以上操作,所有的边都会重新得到一个在0~2之间的权值,再将所有边反向,然后跑一下从1到n的最短路即可。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define M 100005
using namespace std;
inline void Rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<3)+(res<<1)+(c^48);
    while(c=getchar(),c>47);
}
struct node{int to,val;};
vector<node>G[3][M];
int dis[3][M];
int n,m;
bool vis[M];
void Put_edge(int u,int v,int w,int flag){
    G[flag][u].push_back((node){v,w});
}
struct Node{
    int u,dis;
    bool operator <(const Node &cmp)const{return dis>cmp.dis;}
};
void Dijkstra(int st,int f){
    priority_queue<Node>Q;
    memset(dis[f],-1,sizeof(dis[f]));
    memset(vis,0,sizeof(vis));

    dis[f][st]=0;Q.push((Node){st,dis[f][st]});
    while(!Q.empty()){
        Node now=Q.top();Q.pop();
        if(vis[now.u])continue;
        vis[now.u]=true;
        for(int j=0;j<(int)G[f][now.u].size();j++){
            int v=G[f][now.u][j].to,w=G[f][now.u][j].val;
            if(vis[v])continue;
            if(dis[f][v]==-1||dis[f][v]>dis[f][now.u]+w){
                dis[f][v]=dis[f][now.u]+w;
                Q.push((Node){v,dis[f][v]});
            }
        }
    }
}
int main(){
    Rd(n),Rd(m);
    for(int i=1;i<=m;i++){
        int u,v,w0,w1;
        Rd(u),Rd(v),Rd(w0),Rd(w1);
        Put_edge(v,u,w0,0);//将边反向 
        Put_edge(v,u,w1,1);
    }
    Dijkstra(n,0);
    Dijkstra(n,1);
    for(int u=1;u<=n;u++)
        for(int j=0;j<(int)G[0][u].size();j++){
            int v=G[0][u][j].to;
            int cnt=0;
            cnt+=(dis[0][v]!=dis[0][u]+G[0][u][j].val);
            cnt+=(dis[1][v]!=dis[1][u]+G[1][u][j].val);
            Put_edge(v,u,cnt,2);//再次反向 
        }
    Dijkstra(1,2);
    printf("%d\n",dis[2][n]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值