P4141 消失之物(退背包)

洛谷 p4141消失之物 (退背包)


题目链接

思路分析

如果我们去掉删除一个物品的限制,该题便转化为一个01背包了,但目前有删除物品的

限制,跑n次01背包?这样肯定会tle。我们考虑先忽略掉删除物品的限制,求出所有

的方案数,然后再枚举删除哪个物品,减去不符合的方案数,便可得到答案,有点类似容

斥。

算法分析

我们设f[i][1]表示装入物品总体积为i,删除掉目前所枚举物品时的方案数.设

f[i][0]表示装入物品总体积为i,未删除物品时的方案数。

先预处理无限制时的方案数

f[0][1]=f[0][0]=1;
for(int i=1;i<=n;i++){//i为物品编号
		for(int j=m;j>=v[i];j--){
			f[j][0]+=f[j-v[i]][0];
			f[j][0]%=10;//mod10是因为题目要求输出尾数字
		}
	}

接着减掉不符合目前情况的方案数

for(int i=1;i<=n;i++){//i为当前删除物品
		for(int j=1;j<=m;j++){
			if(j-v[i]>=0){
				f[j][1]=(f[j][0]-f[j-v[i]][1]+10)%10;
			}
			else{
				f[j][1]=(f[j][0]+10)%10;
			}
			cout<<f[j][1];
		}
		cout<<endl;
	}

为什么我们要这样递推

f[j][1]=(f[j][0]-f[j-v[i]][1]+10)%10;

我们来分析,f[jv[i]][1]为占用体积为jv[i]且不包含i物品的方案数,

为什么要把它减掉呢?因为f[jv[i]][1]表示所有使用物品i体积达到j的方案数,因为只要加上v[i]此时使用i且体积为j很明显,这是需要减掉的;

这样代码就可以写出来了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
using namespace std;
const int maxn=1e5;
inline int read(){
	int ret=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-f;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		ret=ret*10+(ch^'0');
		ch=getchar();
	}
	return ret*f;
}
int f[maxn][2];
int v[maxn];
int n;
int m;
int main(){
	n=read();
	m=read();
	for(int i=1;i<=n;i++){
		v[i]=read();
	}
	f[0][1]=f[0][0]=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]>=0){
				f[j][1]=(f[j][0]-f[j-v[i]][1]+10)%10;
			}
			else{
				f[j][1]=(f[j][0]+10)%10;
			}
			cout<<f[j][1];
		}
		cout<<endl;
	}
	return 0;
}

完结撒花

posted @   折翼的小鸟先生  阅读(148)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示