| Time Limit: 3000MS | Memory Limit: 30000K | |
| Total Submissions: 21551 | Accepted: 7343 |
Description
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
Input
Output
Sample Input
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
Sample Output
8 4
Source
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int N, V;
int v[110], n[110];
int f[100010];
int main(){
int i, j, k;
while(scanf("%d%d", &N, &V) != EOF, N != 0 || V != 0){
for (i = 0; i < N; i++){
scanf("%d", &v[i]);
}
for (i = 0; i < N; i++){
scanf("%d", &n[i]);
}
memset(f, 0xff, sizeof(int) * (V + 1));
f[0] = 0;
for (i = 0; i < N; i++){
for (j = 0; j <= V; j++){
if (f[j] >= 0){
f[j] = 0;
}else if (j >= v[i] && f[j - v[i]] >= 0 && f[j - v[i]] < n[i]){
f[j] = f[j - v[i]] + 1;
}
}
}
k = 0;
for (i = V; i >= 1; i--)
if (f[i] >= 0) k++;
printf("%d\n", k);
}
return 0;
}
/*
f[i][j]表示前i种钱币,组成面值j,使用第i种钱币最少的数量
明明只是求j的可达性,却通过这么一个巧妙的状态,
使得复杂度减至O(N*V),N是组数
带二进制优化的分组背包是O(sum(log(num[i]))*V)
对于这状态的另一种理解
普通背包
j = 0时
遍历 v[i], 2 * v[i], 3 * v[i],..., n[i] * v[i]
j = 1时
遍历 1 + v[i], 2 + 2 * v[i]...
j = v[i]时
遍历 2 * v[i], 3 * v[i]...
发现和上面重了,这块重复的搜索很浪费啊,怎么解决呢
看到,如果n[i]有无穷大,那么j>=v[i]的会完全与j=0...v[i]-1的重复
但n[i]是有限的,只循环j=0...v[i]-1,有些数量不够,
需要借助之前物品的,就遍历不到了
一种想法是,尽量节省地使用物品i,记录i在凑成j时最少使用的数量
如果之前物品能够凑出j,那就不用使用物品i了
这样节省地遍历下j=0...v[i]-1,算起来时间复杂度还是O(N*V)
*/
219



被折叠的 条评论
为什么被折叠?



