很明显的一个多重背包问题,但是此题极度卡常数,自己写了个分二进制01背包TLE了...然后参看了discuss里的代码,果然是自己写的常数太大
1742 | Accepted | 272K | 2360MS |
#include<cstdio>
#include<cstring>
int a[200],num[200],b[2000],tot;
int q[100020];
bool f[100020];
int main()
{
int i,j,n,ans,price,m,step;
while (scanf("%d%d",&n,&m) == 2)
{
if (n ==0 && m == 0) break;
for (i = 1; i <= n; i++)
scanf("%d",&a[i]);
for (i = 1; i <= n; i++)
scanf("%d",&num[i]);
memset(f,false,sizeof(f));
f[0] = true;
for (i = 1; i <= n; i++)
{
if (a[i] > m) continue;
if (a[i]*num[i] >= m)
{
for (j = a[i]; j <= m; j++) f[j] = f[j] | f[j-a[i]];
}
else
{
step = 0;
while (num[i] > (1<<step))
{
price = a[i]*(1<<step);
for (j = m; j >= price; j--) f[j] = f[j] | f[j-price];
num[i] = num[i]-(1<<step);
step++;
}
price = a[i]*num[i];
for (j = m; j >= price; j--) f[j] = f[j] | f[j-price];
}
}
ans = 0;
for (i = 1; i <= m; i++) if (f[i]) ans++;
printf("%d\n",ans);
}
return 0;
}
此题还有一个特殊的解法,摘自Rainy Days大牛
http://www.cnblogs.com/rainydays/archive/2011/06/13/2080008.html
每次填f[j]时直接由f[j-weight[i]]推出,前提是num[j - weight[i]]<sum[i]
num每填一行都要清零,num[j]表示当前物品填充j大小的包需要至少使用多少个
但是使用这种方法有一个条件,就是要求f数组只能是bool类型。否则会出错。
1742 | Accepted | 656K | 1266MS |
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define maxn 105
#define maxm 100005
bool f[maxm];
int used[maxm], num[maxn], value[maxn];
int n, m;
void input()
{
for (int i =0; i < n; i++)
scanf("%d", &value[i]);
for (int i =0; i < n; i++)
scanf("%d", &num[i]);
}
void work()
{
memset(f, 0, sizeof(f));
f[0] =true;
int sum =0;
for (int i =0; i < n; i++)
{
memset(used, 0, sizeof(used));
for (int j = value[i]; j <= m; j++)
if (!f[j] && f[j - value[i]] && used[j - value[i]] < num[i])
{
f[j] =true;
used[j] = used[j - value[i]] +1;
sum++;
}
}
printf("%d\n", sum);
}
int main()
{
//freopen("t.txt", "r", stdin);
while (scanf("%d%d", &n, &m), n | m)
{
input();
work();
}
return 0;
}
最后再附一个多重背包单调队列优化的解法
http://hi.baidu.com/sy2006ppkdc/item/287eb50a8e2544833c42e217