• ZOJ2770 Burn the Linked Camp 差分约束


    题意:告诉我们一系列的不等式,当然这些不等式都是两个变量之间的差值,而非和值。刘备拥有N个军营,每个军营都有一个人数的上限,现在陆逊的探子来报刘备的[a, b]军营总人数不低过某一个值,现在问根据这些答案陆逊是否能够正确推断出刘备至少在各营一共驻扎了多少部队,如果不能推出,输出“Bad Estimations”。

    分析:根据给定的条件,我们设sum[i]表示刘备前i个军营一共驻扎了多少人,那么每个军营至多有多少人就能够通过不等式列出来。假设一共有三个军营,上限分别为A,B,C,那么有:
    0 <= sum[1] - sum[0] <= A
    0 <= sum[2] - sum[1] <= B
    0 <= sum[3] - sum[2] <= C
    而对于陆逊的探子信息,对[a, b]不少于K人转化为:
    sum[b] - sum[a] >= K
    将sum[x]看做是最短路里面的dis[x]那么根据满足的三角不等式,就能够推出图的边,我们也就能求解出一组合法的满足所有等式的结果。
    接下来要求的刘备总共至少驻扎了多少部队,及设要求的量为M,则满足
    sum[N] - sum[0] >= M  或  sum[0] - sum[N] <= -M
    对于后面的不等式如果设sum[M] = 0,就变成了从N到0的最短路径求解。

    代码如下:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    int N, M, idx, head[1005];
    long long sum[1005];
    char vis[1005];
    int cnt[1005];
    long long dis[1005];
    struct Edge {
        int v, next;
        long long ct; 
    }e[1050005];
    
    void insert(int a, int b, long long ct) {
        e[idx].v = b, e[idx].ct = ct;
        e[idx].next = head[a];
        head[a] = idx++;
    }
    
    void build() {
        for (int i = 1; i <= N; ++i) { 
            insert(i-1, i, sum[i] - sum[i-1]);
            insert(i, i-1, 0);
        }
    }
    
    bool spfa() {
        memset(cnt, 0, sizeof (cnt));
        memset(vis, 0, sizeof (vis));
        memset(dis, 0x3f, sizeof (dis));
        dis[N] = 0, vis[N] = 1;
        cnt[N] = 1;
        queue<int>q;
        q.push(N);
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            vis[v] = 0;
            if (cnt[v] > N) return false;
            for (int i = head[v]; i != -1; i = e[i].next) { 
                if (dis[e[i].v] > dis[v] + e[i].ct) {
                    dis[e[i].v] = dis[v] + e[i].ct;
                    if (!vis[e[i].v]) {
                        q.push(e[i].v);
                        ++cnt[e[i].v];
                        vis[e[i].v] = 1;
                    }
                }
            }
        }
        return true;
    }
    
    int main() {
        int a, b, c;
        while (scanf("%d %d", &N, &M) == 2) {
            idx = 0;
            memset(head, 0xff, sizeof (head));
            for (int i = 1; i <= N; ++i) {
                scanf("%I64d", &sum[i]);
                sum[i] += sum[i-1];    // 求一个前缀和
            }
            for (int i = 0; i < M; ++i) {
                scanf("%d %d %d", &a, &b, &c);
                insert(b, a-1, -c);    // 将a, b, c转化为图中的边
            }
            build();
            if (spfa()) {
                printf("%d\n", -dis[0]);
            } else {
                puts("Bad Estimations");
            }
        }
        return 0;    
    }
  • 相关阅读:
    让php更快提供文件下载
    设计模式 03 设计模式分类
    针对配置文件操作 PHP最常用的四个ini函数
    查找算法
    排序算法
    设计模式 01 统一建模语言基础知识
    关于div和css的一些好习惯
    数据结构的基本概念
    HTML特殊转义字符对照列表
    .htaccess 详解
  • 原文地址:https://www.cnblogs.com/Lyush/p/2956429.html
Copyright © 2020-2023  润新知