• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
二维费用背包问题

二维费用背包问题

​ 给定\(n\)个物品,对于每个物品有容量\(v_i\), 负收益\(w_i\),给定负收益阈值\(k\), 最大容量\(m\), 求保证负收益最低的情况

下最多能装多少物品。

​ 该问题对于集合划分同样可以划分成装与不装两个集合,与01背包相同, 我们需要考虑两个状态量, 负收益和容量,对于保证负收益最低,我们可以通过枚举最终状态得到。

​ 则可以列状态转移方程:

​ \(f[i][j][l] = max(f[i - 1][j][k], f[i - 1][j - v_i][l - k_i] + 1)\)

​ 另外,基于\(f\)函数表达是在当前状态最多能装多少物品, 那么我们可以对\(f[n][m][x] = f[n][m][k]\)枚举,满足该等式的最小\(x\)即为最小负收益。

例题

1022. 宠物小精灵之收服 - AcWing题库

​ 这题需要理解题目,我们设定方程\(f[i][j][k]\) 表示考虑前\(i\)个物品,当精灵球数量不超过\(j\), 消耗\(hp\)不超过\(k\)时的最大捕获精灵数。题目中要求皮卡丘的血量不能低于0, 因此我们输出\(f[n][m][k - 1]\)即可,另外还需要保证最小\(hp\)消耗,可以从已知的状态种进行枚举, 我们枚举\(f[i][j]\)层,找到满足\(f[i][j][x] = f[n][m][k - 1]\) 的最小\(x\)即为消耗

Code

#include <bits/stdc++.h>

using i64 = long long;

const int N = 110, M = 510, K = 1010;

int n, m, k;


int dp[K][M], hp[K][M];

int v[N], h[N];

// dpijk 表示考虑前i个精灵,当背包容量为j时, 皮卡丘hp为k时,的最大精灵球数量, 并且保证皮卡丘hp最大

/*

	将集合划分为,选第i个物品和不选第i个物品,则有转移方程:

	则dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - v[i]][k - v2[i]] + 1);
*/


int main() {
	std::cin >> n >> m >> k;

	for(int i = 1; i <= k; i ++) {
		std::cin >> v[i] >> h[i];
	}

	for(int i = 1; i <= k; i ++) {
		for(int j = n; j >= v[i]; j --) {
			for(int l = m; l >= h[i]; l --) {
			    dp[j][l] = std::max(dp[j - v[i]][l - h[i]] + 1, dp[j][l]);
			}
		}
	}
	
	std::cout << dp[n][m - 1] << " ";
	
	int cost = 0x3f3f3f3f;
    
	for(int i = 0; i <= m - 1; i ++) {
	    if(dp[n][m - 1] == dp[n][i]) {
	        cost = i;
	        break;
	    }
	}
// 	std::cout << cost << "\n";
	std::cout << m - cost;
}
posted on 2023-02-04 23:59  Jack404  阅读(16)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3