P4141 消失之物

P4141 消失之物

◦ ftiasch 有 个物品体积分别是 W1, W2, ..., WN。 由于她的疏忽第 个物
品丢失了。 “要使用剩下的 N - 1 物品装满容积为 的背包,有几种方法
呢?” -- 这是经典的问题了。
她把答案记为 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i,
x) 表格。
◦ N,M<=3000

 

题解

f[x]表示全部物品都可用恰好装满x体积时的方案数,可以用01背包算法
求出。这是总方案数。
然后考虑不选某物品的情况。
g[x]为不选当前物品恰好装满x体积时的方案数。

f[i]加进去当前物品,  g[i]不加

f[i]=f[i]+f[i-w[i]]

f[i]=g[i]+g[i-w[i]]

g[i]=f[i]-g[i-w[i]]

x小于w[i]时, i物品一定不会被选上 g[i]=f[i]
x大于等于w[i]时, i物品可能会被选上,直接求不选的情况比较困难。
总方案数及f[x],不选的方案数可以想为先不选i再最后把i选上,g[x-w[i]]
所以g[x]=f[x]-g[x-w[i]], x从小到大枚举计算g即可。
每次都是线性复杂度,一共n次计算,总复杂度是O(n*m) 

另两种理解方式
◦ 1:也可以用生成函数来理解。
◦ 2:直接考虑程序代码也可以很简单的理解。 

上面有些晦涩难懂,下面看一个仍然晦涩难懂的描述

设 f[ j ][ 0 ] 为体积为 j ,第 i 个物品可以选上的时候,体积为 j 的最大方案数

设 f[ j ][ 1 ] 为体积为 j ,第 i 个物品没选的时候,体积为 j 的最大方案数

假设没有物品消失,那么这就相当于一个01背包问题,f[ x ][ 0 ] 之间的转移

如果有物品消失的话,就相当于在原来的方案数上减去它

     对于物品 i ,如果当前的体积可以放进去,那么它就由 选中的方案 - 没选中的方案,因为之前可能选上了 i (QAQ太艰难了)

     对于物品 i ,如果当前的体积不能放进去,那么直接由 f[ x ][ 0 ] 转移过来,因为在原来的方案里一定是没有选中它的

代码

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=2005;
int n,m;
int w[maxn];
int f[maxn][2];

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) w[i]=read(); 
    f[0][0]=f[0][1]=1;
for(int i=1;i<=n;i++) for(int j=m;j>=w[i];j--) f[j][0]+=f[j-w[i]][0],f[j][0]%=10;
for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(j>=w[i]) f[j][1]=(f[j][0]-f[j-w[i]][1]+10)%10; else f[j][1]=f[j][0]; f[j][1]=f[j][1]%10; printf("%d",f[j][1]); } printf(" "); } return 0; }
原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11359206.html