01 背包的变形

消失之物

链接:https://www.luogu.com.cn/problem/P4141

题目描述

ftiasch 有 n 个物品, 体积分别是 w1,w2,,wn。由于她的疏忽,第 i 个物品丢失了。

“要使用剩下的 n1 物品装满容积为 x 的背包,有几种方法呢?”——这是经典的问题了。

她把答案记为 cnt(i,x) ,想要得到所有i[1,n], x[1,m]cnt(i,x) 表格。

输入格式

第一行两个整数 n,m,表示物品的数量和最大的容积。
第二行 n 个整数 w1,w2,,wn,表示每个物品的体积。

输出格式

输出一个 n×m 的矩阵,表示 cnt(i,x)末位数字

样例 #1

样例输入 #1

3 2
1 1 2

样例输出 #1

11
11
21

提示

【数据范围】
对于 100% 的数据,1n,m2000,且 1vim

【样例解释】
如果物品 3 丢失的话,只有一种方法装满容量是 2 的背包,即选择物品 1 和物品 2。


upd 2023.8.11:新增加五组 Hack 数据。









解答

  • f[j][0]:表示未删物品前的,组成体积为 j 的方案数
  • f[j][1]:表示删除某个物品,组成体积为 j 的方案数
  • 前者就是一个 01 背包问题
  • 后者状态转移主要是 f[j][1] = f[j][0] - f[j - v[i]][1]
  • 解释:因为f[j][0]表示未删,多了部分,需要删除一些,所以枚举每个物品,表示可能删除的,假设当前物品为 if[j - v[i]][1] 表示的是组成体积 j - v[i] 且前面已经删除一个数了
  • 而这个体积只要加上 v[i] ,也就是选这个 i 物品,便可组成体积 j ,我们枚举的也就是删除 i 物品的方案,所以需要删除这一部分
  • 下述 %10 的原因是题目要求输出末尾数字即可
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2010;
int v[N];
int f[N][2];
int n, m;

int main()
{
	cin >> n >> m;

	for (int i = 1; i <= n; i++) cin >> v[i];

	f[0][0] = f[0][1] = 1;
	for(int i = 1; i <= n; i++)
		for (int j = m; j >= v[i]; j--)
		{
			f[j][0] += f[j - v[i]][0];
			f[j][0] %= 10;
		}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (j >= v[i]) f[j][1] = (f[j][0] - f[j - v[i]][1] + 10)  % 10;
			else f[j][1] = f[j][0];
			cout << f[j][1];
		}
		cout << endl;
	}
	
	return 0;
}
posted @   星竹z  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示