【题目描述】
已知一个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行:一个整数,从1分开始连续的可用集合中不多于K张邮票贴出的邮资数。
【样例输入】
5 2
1 3
【样例输出】
13
源代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int k,n,num(0),i[51],f[2000001]; int main() { memset(f,0x3f,sizeof(f)); //初始化最大值。 scanf("%d%d",&k,&n); for (int a=1;a<=n;a++) scanf("%d",&i[a]); //读入邮票的种类。 f[0]=0; //构成面值为0的最少邮票数自然为0。 while (f[num]<=k) //当最少的邮票已经超过最大限度时,停止循环。 { num++; //构成的面值。 for (int b=1;b<=n;b++) if (num>=i[b]) //防止越界。 f[num]=min(f[num],f[num-i[b]]+1); } printf("%d",num-1); return 0; } /* DP思想: 样例的解释: 构成邮资0,所需要邮票张数为0张,f[0]=0 构成邮资1,只能用1分的邮票,所需要邮票张数1张,f[1]=1 构成邮资2,只能用1分的邮票,所需要邮票张数2张,f[2]=1 构成邮资3, (1)若选择使用一张1分的邮票,f[3]=f[2]+1=3 ----> f[3-1]+1 (2)若选择使用一张3分的邮票,f[3]=f[0]+1=1 ----> f[3-3]+1 即:f[3]=min{f[2]+1,f[0]+1}=1 构成邮资4, (1)若选择使用一张1分的邮票,f[4]=f[3]+1=2 ----> f[3-1]+1 (2)若选择使用一张3分的邮票,f[4]=f[1]+1=1 ----> f[3-3]+1 即:f[4]=min{f[3]+1,f[1]+1}=2 最终可得:状态转移方程:f[i]=min{f[i-i[j]]+1}。 */