• 题解 P3720 [AHOI2017初中组]guide


    五分钟出idea,改了三遍代码原来是因为读错题了(

    弱化版

    更好的阅读体验?

    Description

    简化题意:给你一张有向图,有两个边权。对于每条边 ((u,v)),通过它的代价(也就是抱怨)就是两种边权不在 (u)(n) 的最短路上的边权的数量

    Solution

    先来说一下大体思路:

    发现两种 GPS 眼中的边权不一样且不会相互影响,把两个 GPS 分开考虑就好了

    因为要求的是 (u)(n) 的最短路,所以考虑建反图来求。
    规定下面讨论是对应的边是给定的反边。

    我们把每条边都带上三个权值,分别表示两个 GPS 认为的通过时间和通过这条边的抱怨数。

    显然抱怨数初始为 (2),这条边符合几个 GPS 的要求就在减去几。

    已经很明确了,先对两个 GPS 跑最短路,减去对抱怨数的贡献。

    然后对抱怨数跑最短路即可。

    这里我用的是已经死掉的 ( ext{SPFA}),题目数据应该是用脚造的,并没有卡 ( ext{SPFA}),所以跑的飞快,吸口氧是目前的最优解。


    如何确定一条边((u,v)) 是否在 (u)(n) 的最短路上?

    (dis_x) 表示 (x)(n) 的最短路,(e_{u,v}) 表示边 ((u,v)) 的长度,如果满足

    [dis_u + e_{u,v} == dis_v ]

    那么这条边就在 (v)(n) 的最短路上,对应的抱怨数减一。

    下面看代码吧

    Code

    把三个量放进一个图里,写起来码量更短。

    /*
    Work by: Suzt_ilymics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define int long long
    #define LL long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 1e5+5;
    const int MAXM = 5e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    struct edge {
        int from, to, t[3], nxt;
    }e[MAXN << 1];
    int head[MAXN], num_edge = 1;
    
    int n, m;
    int dis[MAXN];
    bool vis[MAXN];
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    void add_edge(int from, int to, int t1, int t2) { 
        e[++num_edge].from = from, e[num_edge].to = to;
        e[num_edge].t[0] = 2, e[num_edge].t[1] = t1, e[num_edge].t[2] = t2;
        e[num_edge].nxt = head[from]; 
        head[from] = num_edge; 
    }
    
    void SPFA(int type) {
        queue<int> q;
        memset(vis, false, sizeof vis);
        memset(dis, 0x3f, sizeof dis);
        q.push(n), dis[n] = 0, vis[n] = true;
        while(!q.empty()) {
            int u = q.front(); q.pop();
            vis[u] = false;
            for(int i = head[u]; i; i = e[i].nxt) {
                int v = e[i].to;
                if(dis[v] > dis[u] + e[i].t[type]) {
                    dis[v] = dis[u] + e[i].t[type];
                    if(!vis[v]) q.push(v), vis[v] = true;
                }
            }
        }
    }
    
    signed main()
    {
        n = read(), m = read();
        for(int i = 1, u, v, t1, t2; i <= m; ++i) {
            u = read(), v = read(), t1 = read(), t2 = read();
            add_edge(v, u, t1, t2);
        }
        for(int k = 1; k <= 2; ++k) {
            SPFA(k); // 分别对两个 GPS 跑最短路
            for(int i = 2; i <= num_edge; ++i) { // 减去最短路上的边的抱怨
                int u = e[i].from, v = e[i].to;
                if(dis[v] == dis[u] + e[i].t[k]) e[i].t[0]--;
            }
        }
    //    for(int i = 2; i <= num_edge; ++i) cout<<e[i].from<<" "<<e[i].to<<" "<<e[i].t[0]<<"
    ";
        SPFA(0);
        printf("%lld", dis[1]);
        return 0;
    }
    
  • 相关阅读:
    消除ie上的:为了有利于保护安全性,IE已限制此网页运行可以访问计算机的脚本或 ActiveX 控件
    JS代码放在head和body中的区别
    iis与apache共用80端口方法集
    如何制作wordpress模板,WordPress模板技术手册
    zt 给博墅加个clocklink时钟
    MSSQL数据库:存储过程实例学习(1)从两个表中取出头两行,然后合并到一个表中
    ecmall 用户后台店铺条幅 在firefox7 以上无法预览的问题
    .NET MVC 实现动态换版
    一道嚼烂的面试题
    [1].gSOAP简介
  • 原文地址:https://www.cnblogs.com/Silymtics/p/14824835.html
Copyright © 2020-2023  润新知