题目描述:
已知一个 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。
输入:
第 1 行: 两个整数,K 和 N。K(1 <= K <= 200)是可用的邮票总数。N(1 <= N <= 50)是邮票面值的数量。
第 2 行至末尾: N 个整数,每行 15 个,列出所有的 N 个邮票的面值,面值不超过 10000。
输出:
一个整数,从 1 分开始连续的可用集合中不多于 K 张邮票贴出的邮资数。
样例输入:
样例输出:
13
分析:
1.数据分析:每个信封最多贴K(K<=200)张邮票,每张邮票的面值不超过10000,能贴出最大的邮资不超过2000000,可用一个数组来表示能够表示贴出每种邮资。
2.算法分析:
(1)搜索:每种邮票最多贴200张,总共50种,朴素的深搜规模将达到50^200。
(2)动态规划:
<1>阶段:能够构成每个面值为阶段。比如能构成的面值为1到V,那么总共为V个阶段。
<2>状态:dp[i]表示构成面值i所需要的最少邮票数.
<3>决策:对于样例数据1和3两种面值的邮票:
构成邮资0:所需要邮票张数为0张,dp[0]=0;
构成邮资1:只能用1分的邮票,所需要邮票张数1张,dp[1]=1;
构成邮资2:只能用1分的邮票,所需要邮票张数2张,dp[2]=1;
构成邮资3:
*1.若选择使用一张1分的邮票,dp[3]=dp[2]+1=3………dp[3-1]+1
*2.若选择使用一张3分的邮票,dp[3]=dp[0]+1=1………dp[3-3]+1
dp[3]=min{dp[2]+1,dp[0]+1}=1;
构成邮资4:
*1.若选择使用一张1分的邮票,dp[4]=dp[3]+1=2………dp[3-1]+1
*2.若选择使用一张3分的邮票,dp[4]=dp[1]+1=1………dp[3-3]+1
dp[4]=min{dp[3]+1,dp[1]+1}=2;
<4>状态转移方程:dp[i]=min{dp[i-a[j]]+1} i>=a[j] 1<=j<=n f[i]<=k;
/*
You should use the statndard input/output
in order to receive a score properly.
Do not use file input and output
Please be very careful.
*/
#include <iostream>
#include <algorithm>
using namespace std;
int Answer;
int dp[2000001];
int main(int argc, char** argv)
{
int T, test_case;
/*
The freopen function below opens input.txt file in read only mode, and afterward,
the program will read from input.txt file instead of standard(keyboard) input.
To test your program, you may save input data in input.txt file,
and use freopen function to read from the file when using cin function.
You may remove the comment symbols(//) in the below statement and use it.
Use #include<cstdio> or #include <stdio.h> to use the function in your program.
But before submission, you must remove the freopen function or rewrite comment symbols(//).
*/
//freopen("input.txt", "r", stdin);
cin >> T;
for (test_case = 0; test_case < T; test_case++)
{
/
/*
Implement your algorithm here.
The answer to the case will be stored in variable Answer.
*/
/
Answer = 0;
int K = 0;
int N = 0;
cin >> K >> N;
int *a = new int[N+1];
for (int i = 0; i < N; i++)
{
cin >> a[i];
}
sort(a, (a + N));
dp[0] = 0;
while (dp[Answer] <= K)
{
Answer++;
dp[Answer] = 999999;
for (int j = 0; j < N && a[j] <= Answer; j++)
{
if (dp[Answer - a[j]] + 1 < dp[Answer])
dp[Answer] = dp[Answer - a[j]] + 1;
}
}
// Print the answer to standard output(screen).
cout << "Case #" << test_case + 1 << endl;
cout << Answer << endl;
delete[]a;
}
return 0;//Your program should return 0 on normal termination.
}