zoukankan      html  css  js  c++  java
  • 同余最短路

    同余最短路其实是一种优化最短路建图的方法。

    通常是解决给定m个整数,求这m个整数能拼凑出多少的其他整数(这m个整数可以重复取)或给定m个整数,求这m个整数不能拼凑出的最小(最大)的整数。

    我们通过一道例题来讲解。

    P3403 跳楼机

    简化一下题意:用a,b,c(这里用a,b,c来代替x,y,z)三个数能组成几个小于h的整数。$h leq 2^{63}-1$

    因为h过大所以直接建图显然是不行的,我们要优化空间。

    我们因为这个跳的顺序是无关的,所以每个数都可以由若干次b/c再加上若干次a而形成的。

    根据带余除法我们知道所有的整数数都可以写成ax+r的形式,其中a是除数,x是商而r是余数。

    我们求出通过b/c操作能到达的最小的mod a余数是r的数,然后用一些算法即可求出能到达多少小于h的整数(到时再讲)。

    这时我们同余最短路就该排上用场了。这个最小即可表示成最短路。

    我们可以让a来做这个除数(其实应该用最小的最优),则r属于$[0,a-1]$。

    我们要求出所有到达所有r的最小值。所以对于每个r建立一个点。

    它可以通过b,c到其它的数(点),所以我们对于每个点u连一条到v=(u+(b/c))%a的边,长度为(b/c)。

    现在从0开始跑最短路即可(初始化dis[0]=0)。

    设余数r的最短路为dis[r],则可以到$frac{h-dis[r]}{a}+1$个整数,统计答案。

    #include <bits/stdc++.h>
    using namespace std;
    const long long MAXA = 1e5 + 10; 
    struct node{
        long long pre, to, val;
    }edge[MAXA * 20];
    long long head[MAXA], tot;
    long long n, h;
    long long a[20];
    long long dis[MAXA], vis[MAXA];
    queue<long long> q;
    void add(long long u, long long v, long long l) {
        edge[++tot] = node{head[u], v, l};
        head[u] = tot;
    }
    void spfa() {
        memset(dis, 0x3f, sizeof(dis));
        dis[0] = 0;
        vis[0] = 1;
        q.push(0);
        while (!q.empty()) {
            long long x = q.front(); q.pop();
            for (long long i = head[x]; i; i = edge[i].pre) {
                long long y = edge[i].to;
                if (dis[y] > dis[x] + edge[i].val) {
                    dis[y] = dis[x] + edge[i].val;
                    if (!vis[y]) {
                        vis[y] = 1;
                        q.push(y);
                    }
                }
            }
            vis[x] = 0;
        }
    }
    long long solve(long long x) {
        long long ret = 0;
        for (long long i = 0; i < a[1]; i++) {
            if (dis[i] <= x) {
                ret += (x - dis[i]) / a[1] + 1;
            }
        }
        return ret;
    }
    int main() {
        n = 3;
        cin >> h;
        for (long long i = 1; i <= n; i++) {
            cin >> a[i];
        }
        for (long long i = 0; i < a[1]; i++) {
            for (long long j = 2; j <= n; j++) {
                add(i, (i + a[j]) % a[1], a[j]);
            }
        }
        spfa();
        cout << solve(h - 1);//他刚开始在1楼所以要-1
        return 0;
    }

    习题:

    [国家集训队]墨墨的等式

     

  • 相关阅读:
    Android Studio 通过 git update 或者 pull 的时候出错及解决办法
    powershell2
    @SuppressWarnings注解用法
    IDEA设置虚拟机参数
    Java爬虫https网页内容报错SSLHandshakeException信任(忽略)所有SSL证书
    Quartz时间配置(周期任务)
    java 字符串转成 json 数组并且遍历
    linux 不能进入系统 Failed to load SELinux policy. Freezing
    linux安装mysql后报错启动不了Starting MySQL. ERROR! The server quit without updating PID file (/var/lib/mysql/localhost.localdomain.pid).
    警告:MySQL-server-5.6.26-1.el7.x86_64.rpm: 头V3 DSA/SHA1 Signature, 密钥 ID 5072e1f5: NOKEY
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12631741.html
Copyright © 2011-2022 走看看