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[ j-v[i] ][1]\)为占用体积为\(j-v[i]\)且不包含\(i\)物品的方案数,
为什么要把它减掉呢?因为\(f[ j-v[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;
}
完结撒花
标签:10,背包,int,之物,ret,ch,物品,include,P4141 来源: https://www.cnblogs.com/rpup/p/13813390.html