Coins
Time Limit: 3000MS | Memory Limit: 30000K | |
Total Submissions: 42834 | Accepted: 14480 |
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.
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
算法分析:
题意:
现在有价值v[1…n]的n种硬币, 它们的数量分别为num[i]个. 然后给你一个m, 问你区间[1,m]内的所有数目, 由之前n种硬币来构造(即选取某些硬币使得这些硬币的价值和等于[1,m]区间的特定数), 最多能构造出这m个数中的多少个?
分析:
多重背包问题.
dp[i][j]=表示用前i种硬币且硬币总价值总价值正好等于j时, 有多少种方法.
初始化: dp为全0,且 dp[0][0]==1.
对于每种硬币, 我们有两种可能的方式处理(多重背包套路):
1. Val[i]*num[i]>= m时, 对当前硬币做一次完全背包即可.
2. Val[i]*num[i]<m时, 我们把当前硬币分成下面k+1类,多次01背包。
最终所求: 所有使得dp[n][j]!=0 的j值得和. (1<=j<=m)
代码实现:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
using namespace std;
const double eps = 1e-8;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1};
const int MOD = 1e9 + 7;
const double pi = acos(-1.0);
const int MAXM=40010;
const int MAXN=100010;
const int M=105;
int n;
struct Node
{
int high,num;
}a[M];
int dp[MAXN];
//01背包过程
void ZERO_ONE_PACK(int cost,int m)
{
for(int i=m;i>=cost;i--)
dp[i]+=dp[i-cost]; //注意递推公式的改变,因为题目要求的为一个累加和
}
//完全背包过程
void COMPLETE_PACK(int cost,int m)
{
for(int i=cost;i<=m;i++)
dp[i]+=dp[i-cost];//注意递推公式的改变,因为题目要求的为一个累加和
}
//多重背包过程
void MULTIPLY_PACK(int cost,int num,int m)
{
if(cost*num>=m)
{
COMPLETE_PACK(cost,m);
return ;
}
int k=1;
while(k<num)
{
ZERO_ONE_PACK(cost*k,m);
num-=k;
k*=2;
}
ZERO_ONE_PACK(cost*num,m);
}
int main()
{
int m;
while(scanf("%d%d",&n,&m)!=EOF&&(n+m))
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i].high);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].num);
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=n;i++)
MULTIPLY_PACK(a[i].high,a[i].num,m); //high本身高度(相当于价值),m该点的限制条件,num该物品的数量
int ans=0;
for(int i=1;i<=m;i++)
if(dp[i]) ans++;
printf("%d\n",ans);
}
return 0;
}