bzoj2287【POJ Challenge】消失之物

題目鏈接:bzoj2287
題目大意:
ftiasch 有 N 個物品, 體積分別是 W1, W2, …, WN。 由於她的疏忽, 第 i 個物品丟失了。 “要使用剩下的 N - 1 物品裝滿容積爲 x 的揹包,有幾種方法呢?” – 這是經典的問題了。她把答案記爲 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i, x) 表格。

題解:
揹包+容斥?
我真的,感覺自己什麼都不會qwq
話說一個物品只能取一次啊只能取一次啊
設f[i][j]表示取前i個滿j的方案數 可以只用一維
c[i][j]表示第i個不取,裝滿容積爲j的揹包的方案數,就是答案
O(NM) 處理f :f[j]+=f[j-v[i]]
c[i][j]的話有三種情況:

  • 若j=0,則c[i][j]=1,顯然
  • 若j<v[i],那麼j中一定不會取到第i個物品,於是c[i][j]=f[j]
  • 若j≥v[i],那麼它就等於總的方案數減去選到了第i個物品的方案數。
    有c[i][j]=f[j]-c[i][j-v[i]],爲什麼c[i][j-v[i]]表示選到了第i個物品的方案數呢?因爲c[i][j-v[i]]表示的是不含i裝了j-v[i]的方案數那麼它加上v[i]之後不就是含i的裝滿了j的嗎

所以真正有用的代碼只有四行。
而我,並不會做。
真是個悲傷個故事。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 2010

int v[maxn],f[maxn],c[maxn][maxn];
//f[i][j]表示取前i個滿j的方案數 可以只用一維
//c[i][j]表示第i個不取,裝滿容積爲j的揹包的方案數
int main()
{
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
    int i,j,n,m;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) scanf("%d",&v[i]);
    memset(f,0,sizeof(f));f[0]=1;
    for (i=1;i<=n;i++)
     for (j=m;j>=v[i];j--)
      f[j]=(f[j]+f[j-v[i]])%10;
    for (i=1;i<=n;i++)
     for (j=0;j<=m;j++)
     {
         if (j==0) c[i][j]=1;
         else if (j<v[i]) c[i][j]=f[j]%10;
         else c[i][j]=(f[j]-c[i][j-v[i]]+10)%10;
     }
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=m;j++)
         printf("%d",c[i][j]%10);
        printf("\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章