POJ 1742
首先多重背包有一种普通的二进制优化,然后这题还可以加一个判断如果,a[i] * c[i] >= m 的话,那就和完全背包一样,不用多重背包。这样应该能过。
第二种做法,是参考了完全背包,完全背包可以用O(nm)的复杂度完成,是因为,遍历m的时候没有数量的限制。那对于这题多重背包,就要考虑在dp里面加上当前物品用掉的数量信息,从而达到完全背包的复杂度。所以用dp[i][j] 表示,当前物品i凑出j元钱时,还剩下多少个i物品。
转移方程也不难写,全部初始化为-1,如果dp[i][j]已经不为0,说明上一种物品就能配出这个钱,所以dp[i][j] = c[i]。如果上一种配不出,那么 if(dp[i][j−a[i]]>0)dp[i][j]=dp[i][j−a[i]]−1 i f ( d p [ i ] [ j − a [ i ] ] > 0 ) d p [ i ] [ j ] = d p [ i ] [ j − a [ i ] ] − 1 说明多用一个当前物品就能配出这个钱。
仔细一想,第一维是可以优化掉的。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 110;
const int MAXM = 100100;
int dp[MAXM];
int n,m,a[MAXN],c[MAXN];
int main()
{
while (scanf("%d%d",&n,&m),n+m)
{
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&c[i]);
memset(dp,-1,sizeof dp);
dp[0] = 0;
for (int i=1;i<=n;i++)
for (int j=0;j<=m;j++)
{
if ( dp[j] != -1 ) dp[j] = c[i];
else if ( j>=a[i] && dp[j - a[i]] >= 1) dp[j] = dp[j-a[i]] - 1;
}
int cnt= 0;
for (int i=1;i<=m;i++) if ( dp[i] != -1 ) cnt++;
printf("%d\n",cnt);
}
return 0;
}