您的位置:首页 > 其它

交大OJ 1069 二哥的硬币(多重背包/单调队列)

2017-11-25 20:41 435 查看
二哥的硬币

Description

快放假了,二哥想给女朋友买一个礼物。

走到商店前,发现钱包里只有硬币了。二哥数了一下,一共有n种硬币,面值分别为A1, A2, …, An,每种硬币的个数分别为C1, C2, …, Cn。

二哥心里没有底,他估计要买的礼物价格不会超过m,但不知道到底要买多少钱的礼物。

二哥的硬币已经很多了,他不想再要更多的硬币了,所以他想知道,用手头这些硬币,可以正好凑出1到m中多少种金额(正好相等,包括1和m)。

Input Format

输入包含多组测试数据。

每组测试数据的第一行是空格分隔的两个整数n和m,

1≤n≤100,1≤m≤100000

1≤n≤100,1≤m≤100000



接下来有2n个整数,分别是面值A1, A2, …, An,以及硬币个数C1, C2, …, Cn,用空白分隔,

1≤Ai≤100000,1≤Ci≤1000

1≤Ai≤100000,1≤Ci≤1000



当读入的n=0且m=0时,表示输入结束;这组数据不需要处理。

Output Format

对于每组测试数据,输出用这些硬币可以正好凑出1到m范围内的多少种金额。

说明

http://poj.org/problem?id=1742

Sample Input

2 5

1 4 2 1

3 10

1 2 4 2 1 1

0 0

Sample Output

4

8

代码如下:

#include <iostream>
#include <cstdio>
using namespace std;
const long long M = 100001;//m<=100000
bool dpall[M];//A[i]:the combination of coins valuing i exists.
long long A[101];
long long C[101];
long long alldata[M];
int coins = 0;
long long sets = 0;
long long m;
void setdpallahead(){
for (int i = 0; i < M; i++) {
dpall[i] = false;
alldata[i] = 0;
}
}

void setdp(){
sets = 0;
setdpallahead();
for (int i = 1; i <= coins; i++) {//start from 1.
if (i==1) {
for(int j=1; j<=C[1]&&j*A[1]<=m; j++){
dpall[j*A[1]] = true;
alldata[++sets] = j*A[i];
}
}//deal with the condition that j==1.
else{//deal with the condition that j>1.
long long prevsets = sets;//present scale
for (int j = 0; j <= prevsets ; j++) {
for (int k = 1; k<=C[i]; k++) {
if (alldata[j]+k*A[i]>m) {//alldata[0]==0,so you can take 0+k*A[i] into thought
break;//finish the preceding "for" recycle.
}
if (!dpall[alldata[j]+k*A[i]]) {//this step records that the value alldata[j]+k*A[i]] exists.
dpall[alldata[j]+k*A[i]] = true;
alldata[++sets] = alldata[j]+k*A[i];
}
}
}
}
}
}

int main(){
scanf("%d%lld", &coins, &m);
while (coins!=0||m!=0) {
for (int i = 1; i <= coins; i++) {
scanf("%lld", &A[i]);
}
for (int i = 1; i <= coins; i++) {
scanf("%lld", &C[i]);
}
setdp();
printf("%lld\n", sets);
scanf("%d%lld", &coins, &m);
}
return 0;
}


多重背包+单调序列:

dpall[i]:记录面值为i的硬币组合是否存在,相当于查找功能,可减少查找算法的时间

alldatas[]:范围用sets存储,alldata[0]=0,面值组合从alldata[1]开始存储,只记录

<=m的面值数额;

sets:存储<=m的面值数值,sets也是alldata中记录的有效长度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OJ