[BZOJ3538]坑爹的GPS

题目描述 Description

有一天,\(FJ\) 买了一辆车,但是,他一手下载了两个\(GPS\) 系统。好了现在麻烦的事情来了,\(GPS\) 有一个功能大概大家也知道,如果\(FJ\) 没有按照\(GPS\) 内置地图的最短路走,\(GPS\) 就会报错来骚扰你。现在\(FJ\) 准备从他的农舍(在1这个点)开车到他的谷屋(\(n\) 这个点)。\(FJ\) 给了你两个\(GPS\) 系统内置地图的信息,他想知道,他最少会听到多少次报错(如果\(FJ\) 走的路同时不满足两个\(GPS\) ,报错次数+2)

输入描述 Input Description

第一行:\(n\) ,\(k\)\(n\) 表示有\(FJ\) 的谷屋在哪,同时保证\(GPS\) 内置地图里的点没有超过\(n\) 的点。\(K\) 表示\(GPS\) 内置地图里的路有多少条,如果两个点没有连接则表明这不是一条通路。
接下来\(k\) 行,每行4个数\(X\) ,\(Y\) ,\(A\) ,\(B\) 分别表示从\(X\)\(Y\) 在第一个\(GPS\) 地图里的距离是\(A\) ,在第二个\(GPS\) 地图里的是\(B\) 。注意由于地形的其他因素\(GPS\) 给出的边是有向边。

输出描述 Output Description

一个值,表示\(FJ\) 最少听到的报错次数。

样例输入 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

样例输出 Sample Output

1

数据范围及提示 Data Size & Hint

\(FJ\) 选择的路线是1 2 4 5,但是\(GPS\) 1认为的最短路是1到3,所以报错一次,对于剩下的2 4 5,两个\(GPS\) 都不会报错。
\(N<=10000\) ,至于路有多少条自己算吧。数据保证所有的距离都在$2^{31}-1 $ 以内。

之前的一些废话

离期中还有两周,离NOIP还有不到三周,下午开始停课计划,是时候拼了!

题解

对于第一个\(GPS\) 求一遍最短路,对第二个也求一遍最短路,注意是以\(n\) 为源点进行最短路,所以还要存一个反图。然后我们尝试建一个报错的地图。在原图上搜索,对于一条边,如果走这一条边不满足第一个\(GPS\) 上的最短路这条路边权加一,同理判断是否第二个的\(GPS\) ,建好图之后再跑一个最短路即可。

代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
#define mem(a,b) memset(a,b,sizeof(a))
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int maxn=10010,maxm=50010;
struct Edge
{
    int u,v,w1,w2,next;
    Edge() {}
    Edge(int _1,int _2,int _3,int _4,int _5):u(_1),v(_2),w1(_3),w2(_4),next(_5) {}
}e[maxm<<1],rev[maxm<<1],E[maxm<<1];
int n,m,first[maxn],rfirst[maxn],First[maxn],c1=-1,c2=-1,ce=-1,a,b,c,d,dis1[maxn],dis2[maxn],dis3[maxn];
bool vis[maxn];
queue<int> Q;
void addEdge(int a,int b,int c,int d)
{
    e[++c1]=Edge(a,b,c,d,first[a]);first[a]=c1;
    rev[++c2]=Edge(b,a,c,d,rfirst[b]);rfirst[b]=c2;
}
void AddEdge(int a,int b,int c){E[++ce]=Edge(a,b,c,0,First[a]);First[a]=ce;}
void SPFA1()
{
    mem(vis,0);mem(dis1,42);
    while(Q.size())Q.pop();
    Q.push(n);vis[n]=1;dis1[n]=0;
    while(Q.size())
    {
        int now=Q.front();Q.pop();
        for(int i=rfirst[now];i!=-1;i=rev[i].next)
            if(dis1[now]+rev[i].w1<dis1[rev[i].v])
            {
                dis1[rev[i].v]=dis1[now]+rev[i].w1;
                if(!vis[rev[i].v])
                {
                    Q.push(rev[i].v);
                    vis[rev[i].v]=1;
                } 
            }
        vis[now]=0;
    }
    return;
}
void SPFA2()
{
    mem(vis,0);mem(dis2,42);
    while(Q.size())Q.pop();
    Q.push(n);vis[n]=1;dis2[n]=0;
    while(Q.size())
    {
        int now=Q.front();Q.pop();
        for(int i=rfirst[now];i!=-1;i=rev[i].next)
            if(dis2[now]+rev[i].w2<dis2[rev[i].v])
            {
                dis2[rev[i].v]=dis2[now]+rev[i].w2;
                if(!vis[rev[i].v])
                {
                    Q.push(rev[i].v);
                    vis[rev[i].v]=1;
                } 
            }
        vis[now]=0;
    }
    return;
}
void SPFA3()
{
    mem(vis,0);mem(dis3,42);
    while(Q.size())Q.pop();
    Q.push(1);vis[1]=1;dis3[1]=0;
    while(Q.size())
    {
        int now=Q.front();Q.pop();
        for(int i=First[now];i!=-1;i=E[i].next)
            if(dis3[now]+E[i].w1<dis3[E[i].v])
            {
                dis3[E[i].v]=dis3[now]+E[i].w1;
                if(!vis[E[i].v])
                {
                    Q.push(E[i].v);
                    vis[E[i].v]=1;
                } 
            }
        vis[now]=0;
    }
    return;
}
int main()
{
    mem(first,-1);mem(rfirst,-1);mem(First,-1);
    n=read();m=read();
    for(int i=1;i<=m;i++)a=read(),b=read(),c=read(),d=read(),addEdge(a,b,c,d);
    SPFA1();SPFA2();
    for(int point=1;point<=n;point++)
        for(int i=first[point];i!=-1;i=e[i].next)
        {
            int cnt=0;
            if(dis1[point]!=dis1[e[i].v]+e[i].w1)cnt++;
            if(dis2[point]!=dis2[e[i].v]+e[i].w2)cnt++;
            AddEdge(point,e[i].v,cnt);
        }
    SPFA3();
    printf("%d\n",dis3[n]);
    return 0;
}

总结

还是比较套路的。

转载于:https://www.cnblogs.com/FYH-SSGSS/p/7719041.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值