【BZOJ2287】【POJ Challenge】消失之物(DP,揹包)

2287: 【POJ Challenge】消失之物

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 804  Solved: 455
[Submit][Status][Discuss]

Description

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

Input

 

第1行:兩個整數 N (1 ≤ N ≤ 2 × 103) 和 M (1 ≤ M ≤ 2 × 103),物品的數量和最大的容積。

第2行: N 個整數 W1, W2, ..., WN, 物品的體積。

Output

 

一個 N × M 的矩陣, Count(i, x)的末位數字。

Sample Input

3 2
1 1 2

Sample Output

11
11
21

HINT

如果物品3丟失的話,只有一種方法裝滿容量是2的揹包,即選擇物品1和物品2。

Source

[Submit][Status][Discuss]

--------------------------------------------------------

算法:

DP,01揹包

做法:

如果沒有物品缺失,那就是簡單的揹包。現在要求缺了第 i 個物品時能裝 j 空間的方案數,我們可以運用補集思想,這個方案數等於不缺 i 物品時的方案數減去一定有 i 物品時的方案數。設 f[j] 表示所有物品都可以用時的方案數,g[i][j]表示不選 i 物品而裝 j 空間時的方案數,則有

j<w[i]   :   g[i][j] = f[j]

j>=w[i] :   g[i][j] = f[j]-g[i][j-w[i]]

當 j<w[i] 時,選物品時不可能選中 i 物品,所以此時 g[i][j]=f[j];而當 j>=w[i] 時,f[j] 中就有選 i 物品而帶來的方案,而此方案正好等於 g[i][j-w[i]] (如果選了 i 物品,那麼選 i 物品之前的空間是 j-w[i],而且每一個物品只能選一次,i 不可能被選兩次,所以選了 i 物品的方案數就是 g[i][j-w[i]])。

這樣,這一道題就運用補集思想巧妙解決了!

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=2010, M=2010;
int n, m;
int w[N], f[M], g[M];

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; ++i) scanf("%d",&w[i]);
	f[0]=1;											// 什麼都不選也是一種方案  
	for(int i=1, j; i<=n; ++i) for(j=m; j>=w[i]; --j) f[j]=(f[j]+f[j-w[i]])%10;
	for(int i=1, j; i<=n; ++i){
		for(j=0; j<w[i]; ++j) g[j]=f[j];
		for(j=w[i]; j<=m; ++j) g[j]=(f[j]-g[j-w[i]]+10)%10;
		for(j=1; j<=m; ++j) printf("%d",g[j]);
		printf("\n");
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章