Guide AHOI2017 洛谷P3720

Description

农场主John最近在网上买了一辆新车,在购买汽车配件时,John不小心点了两次“提交”按钮。导致汽车上安装了两套GPS系统,更糟糕的是John在使用GPS导航时,两套系统常常给出不同的路线。从地图上看,John居住的地区有N个十字路口和M条限定通行方向的道路。第i条道路连接路口A_i(1≤A_i≤N)和B_i(1≤B_i≤N),两个路口之间可能连接有多条道路。允许双向通⾏的道路是将两条单向通⾏的道路隔开所形成的。 John的家在路口1位置,农场在路口N的位置。John可以沿着⼀系列单向道路从家驾车到农场。所有GPS系统的底层地图信息都是⼀样的,区别仅在于对每一条道路的通⾏时间计算不同。对于第i条道路第一套GPS系统计算通行时间为P_i个单位时间,而第二套GPS系统则给出Q_i个单位时间。(所有道路的通行时间都是范围在1到100,000之间的整数)John想要驾车从家到农场。可是,一路上GPS系统总是不厌其烦的提醒John(请从路口X开往路口Y),这是由于John选取了某套GPS系统建议的路径,而另一套GPS系统则认为这不是从路口X到农场的最短路径。我们称之为GPS系统的抱怨。 请你计算一下如果John选择合适的路径到达农场能听到的最少GPS系统的抱怨数 。如果John经过某条道路两套GPS系统都发出抱怨,则抱怨总数加2。

Input

第一行,两个整数N和M。接下来M行,其中第i行描述了道路i的信息,A_i B_i P_i Q_i。

Output

一个整数,表示John一路上能听到的最小抱怨数。

Hint

2≤N≤100000,1≤M≤500000。

Solution

洛谷上面的题都坑爹得一批,指针也坑爹得一批,然后这道题成功地两条都应验了。。。

呃这道题首先是个最短路然后要建三张图跑三次,Dijkstra和SPFA好像都可以不过为了复习SPFA我还是写的SPFA即使它非常地坑人。。嗯然后两个GPS的最短路径各跑一遍,然后用一个for循环预处理出第三个图的边权,也就是这个听抱怨的图的边权,然后只要他没有听GPS1或者2的都要++,都没听就会++两次,然后最后再跑一次SPFA就可以了。

注意事项: 1.指针不能sizeof我要是再被这个坑了我就去自杀一百遍。。。 2.这个因为最后到的是n所以既然是单源最短路径就要从n开始,而且,而且,而且,要,建,反图。 3.好的我还是傻逼还是非常地弱,没了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#define maxn 500005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,node1,x,y,z1,z2,node2,node3;
struct Edge{
    int u;
    int v;
    int w;
    int next;
}edge1[maxn],edge2[maxn],edge3[maxn];
int first1[maxn],last1[maxn],first2[maxn];
int last2[maxn],first3[maxn],last3[maxn];
int dist1[maxn],dist2[maxn],dist3[maxn];
bool vis1[maxn],vis2[maxn],vis3[maxn];
void addedge1(int u,int v,int w){
    edge1[++node1]=(Edge){u,v,w,0};
    if(first1[u]==0)first1[u]=node1;
    else edge1[last1[u]].next=node1;
    last1[u]=node1;
}
void addedge2(int u,int v,int w){
    edge2[++node2]=(Edge){u,v,w,0};
    if(first2[u]==0)first2[u]=node2;
    else edge2[last2[u]].next=node2;
    last2[u]=node2;
}
void addedge3(int u,int v,int w){
    edge3[++node3]=(Edge){u,v,w,0};
    if(first3[u]==0)first3[u]=node3;
    else edge3[last3[u]].next=node3;
    last3[u]=node3;
}
void init(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&x,&y,&z1,&z2);
        addedge1(y,x,z1);
        addedge2(y,x,z2);
        addedge3(y,x,0);
    }
}
void spfa1(int s,int *d){
    queue<int>pq;
    memset(d,inf,sizeof(dist1));
    d[s]=0;
    vis1[s]=true;
    pq.push(s);
    while(!pq.empty()){
        int u=pq.front();
        pq.pop();
        vis1[u]=false;
        for(int k=first1[u];k;k=edge1[k].next){
            int v=edge1[k].v;
            if(d[u]+edge1[k].w<=d[v]){
                d[v]=d[u]+edge1[k].w;
                if(!vis1[v]){
                    vis1[v]=true;
                    pq.push(v);
                }
            }
        }
    }
}
void spfa2(int s,int *d){
    queue<int>pq;
    memset(d,inf,sizeof(dist2));
    d[s]=0;
    vis2[s]=true;
    pq.push(s);
    while(!pq.empty()){
        int u=pq.front();
        pq.pop();
        vis2[u]=false;
        for(int k=first2[u];k;k=edge2[k].next){
            int v=edge2[k].v;
            if(d[u]+edge2[k].w<=d[v]){
                d[v]=d[u]+edge2[k].w;
                if(!vis2[v]){
                    vis2[v]=true;
                    pq.push(v);
                }
            }
        }
    }
}
void spfa3(int s,int *d){
    queue<int>pq;
    memset(d,inf,sizeof(dist3));
    d[s]=0;
    vis3[s]=true;
    pq.push(s);
    while(!pq.empty()){
        int u=pq.front();
        pq.pop();
        vis3[u]=false;
        for(int k=first3[u];k;k=edge3[k].next){
            int v=edge3[k].v;
            if(d[u]+edge3[k].w<=d[v]){
                d[v]=d[u]+edge3[k].w;
                if(!vis3[v]){
                    vis3[v]=true;
                    pq.push(v);
                }
            }
        }
    }
}
int main(){
    init();
    spfa1(n,dist1);
    spfa2(n,dist2);
    for(int i=1;i<=n;i++){
        for(int k=first3[i];k;k=edge3[k].next){
            int u=edge3[k].v;
            if(dist1[i]+edge1[k].w!=dist1[u])edge3[k].w++;
            if(dist2[i]+edge2[k].w!=dist2[u])edge3[k].w++;
        }
    }
    spfa3(n,dist3);
    printf("%d\n",dist3[1]);
    return 0;
}

转载于:https://www.cnblogs.com/virtual-north-Illya/p/10045162.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值