P3056导航

问题描述

约翰在他的新车上装了两个导航系统(GPS),但这两个GPS选择的导航线路常常不同,约翰很是恼火。
约翰所在的小镇地图由N个路口和M条单向道路构成,两个路口间可能有多条道路相连。约翰的家在1号路口,他的农场在N号路口。约翰从家出发,可以经过一系列的道路,最终到达农场。
两个GPS用的都是上述地图,但是,它们计算时间的算法不同。比如,经过第i条道路,1号GPS计算出的时间是Pi分钟,而2号GPS算出的时间是Qi分钟。
约翰想要驾车从家到农场,但是,如果一个GPS认为约翰当前行走的这条路不在它算出的最短路径中,该GPS就会大声抱怨约翰走错了路(每个GPS会算出所有最短路,只要你在其中一条上最短路上它都不会抱怨)。更倒霉的是,有可能两个GPS会同时抱怨约翰当前走的路不是它们推荐的。
请帮助约翰计算,从家到农场过程中,选择怎样的路径才能使得GPS抱怨的次数最少,请算出这个最少的抱怨次数。如果一条路上两个GPS都在抱怨,算两次(+2)抱怨。

输入格式

第1行两个空格间隔的整数,N和M
接下来M行,每行描述一条道路。第i行描述第i条道路,由四个空格间隔的整数构成,Ai,Bi,Pi,Qi,分别表示该条道路的起点、终点、1号GPS计算的耗时、2号GPS计算的耗时。

输出格式

一个整数,表示所求答案。

样例输入

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

样例输出

1

题解

三次spfa()

如果dis[y]-dis[x]==len[i]那么道路i在最短路上

代码

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define maxn1 10004
#define maxn2 100006
#define inf 1e9
int Last[maxn2],End[maxn2],Next[maxn2],St[maxn2],l1[maxn2],l2[maxn2],l3[maxn2];
int n,m;
int Last1[maxn2],End1[maxn2],Next1[maxn2];
int cnt;
int dis1[maxn1],dis2[maxn1],dis3[maxn1];
bool mark[maxn1];
queue<int>q;
void insert(int x,int y,int z1,int z2)
{
    Next[++cnt]=Last[x];
    Last[x]=cnt;
    End[cnt]=y;
    St[cnt]=x;
    l1[cnt]=z1;
    l2[cnt]=z2;

    Next1[cnt]=Last1[y];
    Last1[y]=cnt;
    End1[cnt]=x;
}
void spfa1(){
    int i,j;
    for(i=1;i<=n-1;i++) dis1[i]=inf;
    memset(mark,false,sizeof(mark));
    q.push(n);
    mark[n]=true;
    while(q.size())
    {
        int s=q.front();
        q.pop();
        mark[s]=false;
        for(i=Last[s];i;i=Next[i])
        {
            int en=End[i];
            if(dis1[en]>dis1[s]+l1[i])
            {
                dis1[en]=dis1[s]+l1[i];
                if(mark[en]==false){
                    mark[en]=true;
                    q.push(en);
                }
            }
        }
    }
}
void spfa2(){
    int i,j;
    for(i=1;i<=n-1;i++) dis2[i]=inf;
    memset(mark,false,sizeof(mark));
    q.push(n);
    mark[n]=true;
    while(q.size())
    {
        int s=q.front();
        q.pop();
        mark[s]=false;
        for(i=Last[s];i;i=Next[i])
        {
            int en=End[i];
            if(dis2[en]>dis2[s]+l2[i])
            {
                dis2[en]=dis2[s]+l2[i];
                if(mark[en]==false){
                    mark[en]=true;
                    q.push(en);
                }
            }
        }
    }
}
void spfa3(){
    int i,j;
    for(i=2;i<=n;i++) dis3[i]=inf;
    memset(mark,false,sizeof(mark));
    q.push(1);
    mark[1]=true;
    while(q.size())
    {
        int s=q.front();
        q.pop();
        mark[s]=false;
        for(i=Last1[s];i;i=Next1[i])
        {
            int en=End1[i];
            if(dis3[en]>dis3[s]+l3[i])
            {
                dis3[en]=dis3[s]+l3[i];
                if(mark[en]==false){
                    mark[en]=true;
                    q.push(en);
                }
            }
        }
    }
}
int main()
{
    int i,j;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)
    {
        int x,y,z1,z2;
        scanf("%d%d%d%d",&x,&y,&z1,&z2);
        insert(y,x,z1,z2);
    }
    spfa1();
    spfa2();
    for(i=1;i<=m;i++){
        int tx,ty;
        tx=St[i];
        ty=End[i];
        if(dis1[ty]-dis1[tx]!=l1[i]) l3[i]++;
        if(dis2[ty]-dis2[tx]!=l2[i]) l3[i]++;  
    }
    spfa3();
    cout<<dis3[n];

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值