您的位置:首页 > 其它

USACO-Section3.1 Contact【动态规划(背包问题)】

2018-02-13 12:20 483 查看

题目描述:

已知一个 N 枚邮票的面值集合(如,{1 分,3 分})和一个上限 K —— 表示信封上能够贴 K 张邮票。计算从 1 到 M 的最大连续可贴出的邮资。

例如,假设有 1 分和 3 分的邮票;你最多可以贴 5 张邮票。很容易贴出 1 到 5 分的邮资(用 1 分邮票贴就行了),接下来的邮资也不难:

6 = 3 + 3

7 = 3 + 3 + 1

8 = 3 + 3 + 1 + 1

9 = 3 + 3 + 3

10 = 3 + 3 + 3 + 1

11 = 3 + 3 + 3 + 1 + 1

12 = 3 + 3 + 3 + 3

13 = 3 + 3 + 3 + 3 + 1

然而,使用 5 枚 1 分或者 3 分的邮票根本不可能贴出 14 分的邮资。因此,对于这两种邮票的集合和上限 K=5,答案是 M=13。

[规模最大的一个点的时限是3s]

小提示:因为14贴不出来,所以最高上限是13而不是15

INPUT FORMAT:

第 1 行: 两个整数,K 和 N。K(1 <= K <= 200)是可用的邮票总数。N(1 <= N <= 50)是邮票面值的数量。

第 2 行 .. 文件末: N 个整数,每行 15 个,列出所有的 N 个邮票的面值,每张邮票的面值不超过 10000。

OUTPUT FORMAT:

第 1 行:一个整数,从 1 分开始连续的可用集合中不多于 K 张邮票贴出的邮资数。

SAMPLE INPUT

5 2

1 3

SAMPLE OUTPUT

13

解题思路:

这道题是一个有物品总数限制的背包问题,用数组记录已用的邮票数即可。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#define INF 99999999
using namespace std;
int K,N;
int dp[2000010],a[60];
int main(){
FILE *fin  = fopen ("stamps.in", "r");
FILE *fout = fopen ("stamps.out", "w");
fscanf(fin,"%d%d",&K,&N);
for(int i=0;i<N;i++){
fscanf(fin,"%d",&a[i]);
}
sort(a,a+N);
for(int i=0;i<2000010;i++){
dp[i]=INF;
}
dp[0]=0;
int ccount=1;
while(1){
for(int i=0;i<N;i++){
if(ccount-a[i]>=0)
dp[ccount]=min(dp[ccount],dp[ccount-a[i]]+1);
}
if(dp[ccount]>K){
fprintf(fout,"%d\n",ccount-1);
break;
}
ccount++;
}
exit(0);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 USACO