【题(注意)】【图论】NKOJ3056 导航

14 篇文章 0 订阅

NKOJ3056 导航
时间限制 : 10000 MS 空间限制 : 131072 KB

问题描述
约翰在他的新车上装了两个导航系统(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

提示
样例解释:
约翰选择路径:1->2->4->5,1号GPS会在1->2抱怨(它会推荐走1->3这条路)。
但是,剩下的路径2->4->5,两个GPS都不会抱怨, 因为它们算出的从2到5最短路径都是走这条路。
数据范围:
对于30%的数据,1<=N<=20,1<=M<=20
对于100%的数据,1<=N<=10000,1<=M<=50000,0<=Pi,Qi<=100000

来源 感谢nodgd放题

思路:
处理出每个导航在每个节点处的理论路径:
每个节点的最短路需要实时更新->跑返图
再将每条边导航叫的次数作为权值跑一次最短路

注意:处理每条边上叫的次数时用“g1.dis[y]+g1.len[t]==g1.dis[x]”判断是否是理论路径,不用也不能记从终点到该点的路径,因为通过该点可能到几个点都不叫,但路径只能记一个点。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int needn=10003; 
const int needm=50003;
const long long inf=(1LL<<62);

int n,m;
//........................................................
inline int in_()
{
    char t=getchar();
    while(t<'0'||t>'9') t=getchar();
    int d=0;
    for(;t<='9'&&t>='0';t=getchar()) d=(d<<1)+(d<<3)+t-'0';
    return d;
}
//........................................................
int la[needm],en[needm],fi[needn];
int las[needm],ens[needm],fis[needn];
bool inq[needn];
queue<int> q;

struct fy
{
    int len[needm];//,next[needn];
    long long dis[needn];
    void spfa(int s)
    {
        for(int i=1;i<=n;i++) dis[i]=inf,inq[i]=false;
        dis[s]=0;q.push(s);inq[s]=true;
        int x,y,t;
        while(!q.empty())
        {
            x=q.front();q.pop();inq[x]=false;
            for(t=fi[x];t;t=la[t])
            {
                y=en[t];
                if(dis[y]>dis[x]+len[t])
                {
                    dis[y]=dis[x]+len[t];
                    //next[y]=x;
                    if(inq[y]==false) q.push(y),inq[y]=true;
                }
            }
        }
    }
}  g1,g2;

int tot=0;
void add(int a,int b,int c1,int c2)
{
    tot++;
    la[tot]=fi[b];
    fi[b]=tot;
    en[tot]=a;
    las[tot]=fis[a];
    fis[a]=tot;
    ens[tot]=b;
    g1.len[tot]=c1,g2.len[tot]=c2;
}
//........................................................
int ans=1e9;
int dis[needn];

void spfa(int s)
{
    for(int i=1;i<=n;i++) dis[i]=1e9,inq[i]=false;
    dis[s]=0;
    q.push(s),inq[s]=true;
    int x,y,t,len;
    while(!q.empty())
    {
        x=q.front(),q.pop(),inq[x]=false;
        for(t=fis[x];t;t=las[t])
        {
            y=ens[t];
            len=2;
            if(g1.dis[y]+g1.len[t]==g1.dis[x]) len--;
            if(g2.dis[y]+g2.len[t]==g2.dis[x]) len--;
            /*if(g1.next[x]==y) len--;
            if(g2.next[x]==y) len--;*/
            if(dis[y]>dis[x]+len)
            {
                dis[y]=dis[x]+len;
                if(!inq[y])
                {
                    q.push(y);
                    inq[y]=true;
                }
            } 
        }
    }
}

//........................................................

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,a,b,c1,c2;i<=m;i++) 
    {
        a=in_(),b=in_(),c1=in_(),c2=in_();
        add(a,b,c1,c2);
    }
    g1.spfa(n),g2.spfa(n);
    spfa(1);
    printf("%d",dis[n]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值