「分数规划」学习笔记及做题记录

news/2024/10/5 12:27:00

「分数规划」学习笔记及做题记录

做题时发现不会分数规划,赶紧来学一下。

分数规划用于求解下面一类问题:

\(n\) 个物品,第 \(i\) 个物品的价值为 \(a_i\),费用为 \(b_i\)。从中选择若干个物品,使得价值与费用的比值 \(\dfrac{\sum a}{\sum b}\) 最大/最小。

另一种更严谨的表示方法是:给第 \(i\) 个物品钦定 \(w_i \in \{1, 0\}\) 表示选/不选该物品,使得 \(\dfrac{\sum_{i=1}^{n} w_i \times a_i}{\sum_{i=1}^{n} w_i \times b_i}\) 最大。

分数规划使用二分法来求解该问题。以求最大值为例,二分比值 \(x\),求解判断问题:是否存在方案,使比值大于等于 \(x\) (由于是实数二分,加不加等于其实无所谓)。那么式子化为:

\[\dfrac{\sum_{i=1}^{n} w_i \times a_i}{\sum_{i=1}^{n} w_i \times b_i} \ge x \\ \Longrightarrow \sum_{i=1}^{n} w_i \times (a_i - x \times b_i) \ge 0 \]

这样,只需求出不等号左边式子的最大值。如果该最大值不小于 \(0\),说明比值可以达到 \(x\),否则不可以。

可以发现,这样转化问题的最大好处是:我们消去了除法。如果把 \(a_i - x \times b_i\) 看作第 \(i\) 个物品的新权值 \(c_i\),那么我们只要研究如何取到这一个权值的和的最大值,而不用研究两个权值的比,这往往能带来极大的便利。

而分数规划的主要难点也就在于求出新权值 \(c_i\) 的最大和。下面以几道例题为例来讲解。(由于二分的过程是类似的,下面只研究如何求出新权值的最大和)

例题

I. [USACO18OPEN] Talent Show G

问题转化后:第 \(i\) 个物品的权值为 \(a_i\),费用为 \(w_i\),并且总费用不小于 \(W\)

可以用背包 dp 来求解。设 \(f(i, v)\) 表示在前 \(i\) 个物品中,选择若干个使得费用和为 \(v\) 时,权值的最大值。但这里有一个问题:\(w_i \le 10^6\),因此 dp 数组的第二维要开到 \(n \times w \le 2.5 \times 10^5\),这样的时空复杂度都是无法接受的。但我们注意到,大于等于 \(W\) 的重量都可以直接视为 \(W\),这样并不改变答案。也就是说,\(f(i, W)\) 表示的实际上是费用和不小于 \(W\),权值的最大值。转移的时候,使用“我为人人”的转移方法,可以使代码实现更简洁。详见代码。

bool check(double x)
{vector<double> a(n + 1);for(int i = 1; i <= n; i++)a[i] = t[i] - x * w[i];vector<vector<double>> f(n + 1, vector<double>(W + 1, -1e9));f[0][0] = 0;for(int i = 1; i <= n; i++){copy(f[i - 1].begin(), f[i - 1].end(), f[i].begin()); // 如果不用滚动数组,必须写这一行for(int v = 0; v <= W; v++) // “我为人人” {int j = min(W, v + w[i]);f[i][j] = max(f[i][j], f[i - 1][v] + a[i]);}}return f[n][W] >= 0;
}

提交记录

II. [JSOI2016] 最佳团体

树上背包即可。

void dfs(int u)
{sz[u] = 1, f[u][1] = a[u];for(int v: G[u]){dfs(v);sz[u] += sz[v];for(int i = min(m, sz[u]); i > 1; i--){for(int j = max(0, i + sz[v] - sz[u]); j <= min(i - 1, sz[v]); j++)f[u][i] = max(f[u][i], f[v][j] + f[u][i - j]);}}
}bool check(double x)
{for(int i = 1; i <= n; i++)a[i] = val[i] - x * w[i];fill(f.begin(), f.end(), vector<double>(m + 1, -1e9));dfs(rt);return f[rt][m] >= 0; 
}

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

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

相关文章

WMCTF 2024 wp

WEBPasswdStealer前言本来题目叫PasswdStealer的:)考点就是CVE-2024-21733在SpringBoot场景下的利用。漏洞基本原理参考 https://mp.weixin.qq.com/s?__biz=Mzg2MDY2ODc5MA==&mid=2247484002&idx=1&sn=7936818b93f2d9a656d8ed48843272c0不再赘述。SpringBoot场景…

Z-library数字图书馆镜像地址及客户端/app(持续更新)

Z-library数字图书馆介绍 Z-library,被誉为全球范围内最为庞大的数字图书馆之一,其藏书量之丰富令人叹为观止,总计囊括了超过9,826,996册电子书及84,837,646篇学术期刊文章。这座庞大的知识宝库覆盖了从经典文学巨著到前沿理工学科,从人文艺术瑰宝到专业学术论文的广泛领域…

T3 玄泡面求调

觉得模拟赛题解还是单独放出来比较好。 A.挤压 好像不难?二进制表示下的平方展开没推出来,不然就成简单题了。 首先我们需要知道对于一个数 \(x\),把它拆成 29 位的二进制形式后,用 \(s_i\) 表示二进制下第 \(i\) 位上的数,那么其实这个数就是 \((\overline{s_{29} s_{28}…

c盘清理指南

1.清理缓存文件 快捷键Win+R输入%temp%2.磁盘清理直接win键+搜索磁盘清理3.休眠文件关闭关机时下次开机powercfg -h off 有需要休眠文件的时候再powercfg -h on 4.临时文件 设置→系统→存储→临时文件,删除! 5.把ubuntu从c移到d出现0x80073cf6错误代码 https://www.yundongf…

轻松找到并查看织梦CMS的数据库配置文件,从而获取数据库连接信息

使用FTP工具连接到服务器。 导航到 /var/www/html/include 目录。 打开 config.inc.php 文件。使用SSH连接到服务器。 切换到相应目录:bashcd /var/www/html/include使用文本编辑器打开文件:bashvi config.inc.php通过以上步骤,你可以轻松找到并查看织梦CMS的数据库配置文件…

Leetcode 1631. 最小体力消耗路径

1.题目基本信息 1.1.题目描述 你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你…

使用ValueConverters扩展实现枚举控制页面的显示

1、ValueConverters 本库包含了IValueConverter接口的的最常用的实现,ValueConverters用于从视图到视图模型的值得转换,某些情况下,可用进行反向转换。里面有一些抽象类、模板类的定义,可以继承这些类实现一些自己想要实现的功能,方便快速。像BoolToValueConverterBase、V…

【Shiro】3.Springboot实现缓存

最近已经快速入门了Shiro。对于登录、授权、认证等方法,每次都是从数据库直接查询。如果登录的人员过多,对数据库来说,是一项压力。如何减轻数据库的压力。EhCache 实现缓存 集成 Redis 实现 Shiro 缓存(推荐使用)在此之前,我们已经简单学会EhCache 和Reids的使用。 EhCa…