Coins
Time Limit: 3000MS | Memory Limit: 30000K | |
Total Submissions: 21637 | Accepted: 7358 |
Description
People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar.One day Tony opened his money-box and found there were some coins.He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.
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.
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
The input contains several test cases. The first line of each test case contains two integers n(1<=n<=100),m(m<=100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000). The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.
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)
不过奇怪了,开始写的是
j = v[i] to V
if (...)中不带j >= v[i]的判断,结果RE了
其实应该WA,因为j=0...v[i]-1的f[j]没有清0...
改完后就AC了。奇怪为啥是RE...
*/