Codeforces 1955H 最小费用流 / DP

题意

传送门 Codeforces 1955H The Most Reckless Defense

题解

不同塔对敌人的贡献是独立的。考虑任一座塔,赋予其 r r r的攻击范围,则其对敌人的造成伤害的上界为 n m p < 3 l g , l g = 13 nmp<3^{lg},lg=13 nmp<3lg,lg=13,则当 r ≥ l g r\geq lg rlg,则塔对敌人造成的伤害与初始化增加的生命值两者的总贡献为正,此时显然取 r = 0 r=0 r=0更优。故只需考虑 r < l g r< lg r<lg的情况。分别以塔和 r r r为左右节点构造带权二分图,问题转化为求匹配数任意情况下的最小权匹配。构造邻接矩阵的时间复杂度为 O ( l g 3 × k ) O(lg^{3}\times k) O(lg3×k)

最小费用流

新增源点、汇点,将带权二分图建模为网络流,构造势函数保证边权非负,使用dijkstra算法不断增广。图中带负权边,为了构造势函数,可以初始化时使用Bellman-Ford算法;而此处的图具备良好的性质,即每次增广所用的边数 k k k都是相等的(不妨假设增广路中每条反向边可以抵消一条原边),即 k = 1 k=1 k=1,此时只需为每条边加上一个 d d d转化为非负权值,每次求增广路时减去 k × d k\times d k×d即可还原得到原始路径权值。

那么对于流量任意的最小费用流,只需在残余网络存在权值为负的路径情况下不断增广。令二分图左部点数量为 n = l g n=lg n=lg,右部点数量为 m = k m=k m=k,则总时间复杂度 O ( n 2 m log ⁡ ( n + m ) ) O\big(n^2m\log(n + m)\big) O(n2mlog(n+m))

tourist的这份提交似乎实现了一种不需要保证完备匹配的Hungarian算法,其复杂似乎是 O ( n 2 m ) O(n^2m) O(n2m)

#include <bits/stdc++.h>
using namespace std;
constexpr int INF = 1e9;
struct MinimumCostFlow {
    struct Edge {
        int to, cost, cap, rev;
    };
    vector<vector<Edge>> g;
    vector<int> h, used, ds;
    vector<int> prevv, preve;
    int delta;

    MinimumCostFlow(int n, int d) : g(n), h(n), used(n), ds(n), prevv(n), preve(n), delta(d) {
    }

    void add_edge(int from, int to, int cost, int cap) {
        g[from].push_back({to, cost, cap, (int)g[to].size()});
        g[to].push_back({from, -cost, 0, (int)g[from].size() - 1});
    }

    pair<int, int> min_cost_flow(int s, int t) {
        fill(h.begin(), h.end(), 0);
        int flow = 0, res = 0;
        for (;;) {
            fill(used.begin(), used.end(), 0);
            fill(ds.begin(), ds.end(), INF);
            using P = pair<int, int>;
            ds[s] = 0;
            priority_queue<P, vector<P>, greater<P>> q;
            q.push({ds[s], s});
            while (!q.empty()) {
                int v = q.top().second;
                q.pop();
                if (used[v]) {
                    continue;
                }
                used[v] = 1;
                for (int i = 0; i < (int)g[v].size(); ++i) {
                    auto [to, cost, cap, _] = g[v][i];
                    if (cap > 0) {
                        if (ds[to] > ds[v] + cost + h[v] - h[to]) {
                            ds[to] = ds[v] + cost + h[v] - h[to];
                            prevv[to] = v;
                            preve[to] = i;
                            q.push({ds[to], to});
                        }
                    }
                }
            }
            if (ds[t] == INF) {
                break;
            }
            for (int v = 0; v < (int)g.size(); ++v) {
                if (ds[v] != INF) {
                    h[v] += ds[v];
                }
            }
            if (h[t] - delta >= 0) {
                break;
            }
            int d = INF;
            for (int v = t; v != s; v = prevv[v]) {
                auto &e = g[prevv[v]][preve[v]];
                d = min(d, e.cap);
            }
            flow += d;
            res += d * h[t];
            for (int v = t; v != s; v = prevv[v]) {
                auto &e = g[prevv[v]][preve[v]];
                e.cap -= d;
                g[e.to][e.rev].cap += d;
            }
        }
        return {flow, res};
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tt;
    cin >> tt;
    while (tt--) {
        int n, m, k;
        cin >> n >> m >> k;
        vector<string> mat(n);
        for (int i = 0; i < n; ++i) {
            cin >> mat[i];
        }
        vector<array<int, 3>> towers(k);
        for (int i = 0; i < k; ++i) {
            auto &[x, y, p] = towers[i];
            cin >> x >> y >> p;
            x -= 1, y -= 1;
        }
        const int mx_lg = 12;
        vector<vector<int>> cost(k, vector<int>(mx_lg));
        auto judge = [&](int x, int y) {
            return 0 <= x && x < n && 0 <= y && y < m;
        };
        int p3 = 1;
        for (int r = 1; r <= mx_lg; ++r) {
            p3 *= 3;
            for (int i = 0; i < k; ++i) {
                int sum = 0;
                auto [x, y, p] = towers[i];
                for (int dx = -r; dx <= r; ++dx) {
                    for (int dy = -r; dy <= r; ++dy) {
                        int nx = x + dx, ny = y + dy;
                        if (judge(nx, ny) && dx * dx + dy * dy <= r * r && mat[nx][ny] == '#') {
                            sum += p;
                        }
                    }
                }
                cost[i][r - 1] = p3 - sum;
            }
        }

        auto matching = [&]() {
            int s = mx_lg + k, t = s + 1;
            int n = t + 1;
            const int delta = 2e6;
            MinimumCostFlow mcf(n, delta);
            for (int i = 0; i < mx_lg; ++i) {
                mcf.add_edge(s, i, 0, 1);
            }
            for (int i = 0; i < k; ++i) {
                mcf.add_edge(mx_lg + i, t, 0, 1);
            }
            for (int i = 0; i < k; ++i) {
                auto &c = cost[i];
                for (int j = 0; j < (int)c.size(); ++j) {
                    if (c[j] >= 0) {
                        continue;
                    }
                    mcf.add_edge(j, mx_lg + i, delta + c[j], 1);
                }
            }
            auto [flow, res] = mcf.min_cost_flow(s, t);
            res -= flow * delta;
            return res * -1;
        };
        cout << matching() << '\n';
    }

    return 0;
}
DP

由于 l g lg lg非常小,可以使用状态压缩DP更加方便地求解上述最小权匹配问题。总时间复杂度 O ( k × l g 2 l g ) O(k\times lg2^{lg}) O(k×lg2lg)

#include <bits/stdc++.h>
using namespace std;
constexpr int INF = 1e9;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tt;
    cin >> tt;
    while (tt--) {
        int n, m, k;
        cin >> n >> m >> k;
        vector<string> mat(n);
        for (int i = 0; i < n; ++i) {
            cin >> mat[i];
        }
        vector<array<int, 3>> towers(k);
        for (int i = 0; i < k; ++i) {
            auto &[x, y, p] = towers[i];
            cin >> x >> y >> p;
            x -= 1, y -= 1;
        }
        const int mx_lg = 12;
        vector<vector<int>> cost(k, vector<int>(mx_lg));
        auto judge = [&](int x, int y) {
            return 0 <= x && x < n && 0 <= y && y < m;
        };
        int p3 = 1;
        for (int r = 1; r <= mx_lg; ++r) {
            p3 *= 3;
            for (int i = 0; i < k; ++i) {
                int sum = 0;
                auto [x, y, p] = towers[i];
                for (int dx = -r; dx <= r; ++dx) {
                    for (int dy = -r; dy <= r; ++dy) {
                        int nx = x + dx, ny = y + dy;
                        if (judge(nx, ny) && dx * dx + dy * dy <= r * r && mat[nx][ny] == '#') {
                            sum += p;
                        }
                    }
                }
                cost[i][r - 1] = p3 - sum;
            }
        }
        auto _min = [&](int &x, int y) {
            x = min(x, y);
        };
        vector<int> dp(1 << mx_lg, INF);
        dp[0] = 0;
        for (int i = 0; i < k; ++i) {
            for (int j = (1 << mx_lg) - 1; j >= 0; --j) {
                for (int l = 0; l < mx_lg; ++l) {
                    if (~j >> l & 1) {
                        _min(dp[j | 1 << l], dp[j] + cost[i][l]);
                    }
                }
            }
        }
        int res = 0;
        for (int i = 0; i < 1 << mx_lg; ++i) {
            res = min(res, dp[i]);
        }
        res *= -1;
        cout << res << '\n';
    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/588805.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-6.3--Cortex-A7寄存器介绍

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

Numerical Analysis(byRichard.L..Burden)【pdf高清英文原版】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

HarmonyOS 4.0(鸿蒙开发)01 - 怎么学习鸿蒙引导篇

作为公司的全栈开发工程师 以及 未来的发展是有鸿蒙这个阶段的&#xff0c;以及本身具有这个技术栈由此后续会分享自己在实战中学习到的东西&#xff0c;碰到的bug都会分享出来&#xff0c;这是引导篇期待后续的更新 学习目标&#xff1a; 理解HarmonyOS操作系统的架构和开发…

目标检测算法YOLOv3简介

YOLOv3由Joseph Redmon等人于2018年提出&#xff0c;论文名为&#xff1a;《YOLOv3: An Incremental Improvement》&#xff0c;论文见&#xff1a;https://arxiv.org/pdf/1804.02767.pdf &#xff0c;项目网页&#xff1a;https://pjreddie.com/darknet/yolo/ 。YOLOv3是对YOL…

解决IDEA下springboot项目打包没有主清单属性

1.问题出现在SpringBoot学习中 , 运行maven打包后无法运行 报错为spring_boot01_Demo-0.0.1-SNAPSHOT.jar中没有主清单属性 SpringBoot版本为 2.6.13 Java 版本用的8 解决方法 1.执行clean 删除之前的打包 2.进行打包规范设置 2.1 3.进行问题解决 (借鉴了阿里开发社区) 使用…

利用PDAL2.7.1 实现点云滤波

利用PDAL2.7.1 实现点云滤波 本文介绍利用PDAL实现点云滤波方法&#xff0c;包含pipeline命令行运行、C代码两种方法&#xff0c;C代码分别介绍对点云文件进行滤波、点云全部在内存中进行滤波的pdal两种调用方法。并简单探究pdal的设计结构。 目录 1 pipeline命令调用方法2 文…

R语言4版本安装mvstats(纯新手)

首先下载mvstats.R文件 下载mvstats.R文件点此链接&#xff1a;https://download.csdn.net/download/m0_62110645/89251535 第一种方法 找到mvstats.R的文件安装位置&#xff08;R语言的工作路径&#xff09; getwd() 将mvstats.R保存到工作路径 在R中输入命令 source(&qu…

飞腾D2000+X100 TYPE6全国产核心板

飞腾D2000X100 TYPE6核心板 产品概述 飞腾D2000X100 TYPE6核心板为增强型自主控制器核心板&#xff0c;其核心芯片CPU采用飞腾D2000/8核工业版CPU、飞腾桥片X100、双通道DDR4L插槽、PHY芯片等。 产品特点 l 基于飞腾D2000X100桥片 l 丰富的PCIE扩展资源&#xff0c;一路PCIE…

C++入门系列-函数重载

&#x1f308;个人主页&#xff1a; 羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 函数重载 自然语言当中&#xff0c;一个词可以有多重含义&#xff0c;人们可以通过上下文来判断该词真实的含义&#xff0c;即该词被重载了。 函数重载的概念 函数重载&#x…

A4的PDF按A3打印

先用办公软件打开&#xff0c;比如WPS。 选择打印-属性。 纸张选A3&#xff0c;如果是双面打印&#xff0c;选短边装订&#xff0c;然后在版面-页面排版-每张页数&#xff08;N合1&#xff09;选2。 不同打印机的具体配置可能不一样&#xff0c;但大体都是这个套路。

rocketmq dashboard控制台中topic状态无法展示

现象 在使用rocketmq控制台查看topic状态和订阅状态时&#xff0c;出现错误和没有信息的情况。 原因 rocketmq控制台版本问题&#xff0c;最新版本为1.0.1&#xff0c;支持rocketmq5版本&#xff0c;如果使用rocketmq4版本的服务无法兼容对应的数据。同理1.0.0版本也无法兼容ro…

中兴ZXV10 B860AV2.1机顶盒刷机

移动的电视盒子如果不续费&#xff0c;连桌面都进不去&#xff0c;趁着五一有空把系统刷了。整体上比较顺利。 注意这个盒子只有两个螺丝&#xff0c;盒子上已经标识&#xff0c;如上图左上角和右下角。盒子里面有卡扣&#xff0c;卸掉螺丝直接扣是很难打开的&#xff0c;需要用…

【CLion】clion无法加载或找不到cmakekists文件

一、问题表象 最近工作中&#xff0c;在git pull远程仓库最新版本程序后&#xff0c;平时打开CLion自动加载的工程CMakeLists文件突然失效&#xff08;显示找不到可编译的文件&#xff09;&#xff0c;无法debug程序。 二、原因分析 基于平时的编码经验和之前git pull也出现…

深度学习之基于CIFAR10图像分类可视化

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习之基于CIFAR-10图像分类可视化项目简介 一、项目背景 随着深度学习和计算机视觉技术的飞速发展&#xff…

边缘计算含义与应用简析

边缘计算概述 边缘计算使数据存储和处理靠近生成或收集数据的位置&#xff0c;而不是在位于数千公里的服务器上。它将通过保持灵活性在边缘无缝可靠地部署服务。它比云计算更安全&#xff0c;因为不需要传输数据。因此&#xff0c;在将数据从边缘移动到云端时&#xff0c;不用…

基于React实现B站评论区

今天继续来学习一下React&#xff0c;使用React实现B站评论区&#xff0c;如下图&#xff1a; 在使用React开发类似B站评论区的功能时&#xff0c;我们需要考虑以下几个关键点来构建一个基本的评论系统&#xff1a; 1. 设计组件结构 首先&#xff0c;设计组件结构是关键。至少…

什么是弹性云服务器(ECS)

弹性云服务器&#xff08;Elastic Cloud Server&#xff0c;ECS&#xff09;是由CPU、内存、操作系统、云硬盘组成的基础的计算组件。弹性云服务器创建成功后&#xff0c;您就可以像使用自己的本地PC或物理服务器一样&#xff0c;在云上使用弹性云服务器。 云服务器ECS&#x…

Re71:读论文 Sequence to Sequence Learning with Neural Networks

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;Sequence to Sequence Learning with Neural Networks ArXiv下载地址&#xff1a;https://arxiv.org/abs/1409.3215 本文是2014年NeurIPS论文&#xff08;那时候这个会还叫NIPS&#xf…

HBase的简单学习四

一 HBase的进阶 1.1 hbase的写流程 Hbase读取数据的流程&#xff1a; 1&#xff09;是由客户端发起读取数据的请求&#xff0c;首先会与zookeeper建立连接 2&#xff09;从zookeeper中获取一个hbase:meta表位置信息&#xff0c;被哪一个regionserver所管理着 hbase:meta表…

C语言:循环结构

循环结构 1. for循环概念举例示例结果分析 补充 2. while循环概念举例示例结果分析补充 3. do-while循环概念举例示例结果分析 补充 4.循环控制举例示例结果分析 C语言中的循环结构是一种重要的编程构造&#xff0c;它允许我们重复执行一段代码&#xff0c;直到满足某个条件为止…
最新文章