【算法】【动态规划】 邮票问题

题目描述:

 已知一个 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 张邮票贴出的邮资数。

样例输入:

5 2
1 3

样例输出:

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.
}


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值