codeup22345 邮票问题

codeup22345  邮票问题

时空限制    1000ms/128MB

题目描述

 给定一个信封,最多只允许粘贴N(N<=100)张邮票,我们现在有m(m<=100)种邮票,面值分别为:x1,x2,…….xm分(xi<=255,为正整数),并假设各种邮票都有足够多张.

       要求计算所能获得的邮资最大范围,即求最大值MAX,使在1—MAX之间的每一个邮资值都能得到.

       例如:N=4,有2种邮票,面值分别为1分,4分,于是可以得到1----10分,和12分,13分,16分的邮资,由于不能得到11分和15分,所有邮资的最大范围是MAX=10.    

输入

从键盘输入一个文本文件的文件名 , 该文件第 1 行为最多粘贴的邮票数 N; 2 行为邮票种数 m, 以下 m 行各有一个数字 , 表示邮票的面值 xi.

输出

1.       若最大范围为空,则在屏幕上输出MAX=0

2.       若最大范围不为空,则把结果输出到屏幕上.

样例输入

4
2
1
4

样例输出

MAX=10

分析

本题可以看成是一个集合问题即求在贴的邮票不多于n张的可满足条件的邮资集。

集合问题的关键在于判定元素是否在集合中,对于本题而言是判断某个邮资是否在贴不多于n张邮票可满足。

这个判断问题可以用递归的方法解决

设当前考虑的邮资值为maxv,最多允许贴n张邮票,记为(maxv,n).如果首先贴一张面值为xi的邮票,那么剩下的问题是(maxv-xi,n-1)的问题。如果(maxv-xi,n-1)可解,那么(maxv,n)问题也可解

 进一步这个递归的算法可以转化为递推的算法来解决。设f[value]表示邮资为value时所需最少的邮票数,f[maxv]=min{f[maxv-x[i]]+1}。当f[value]<=n时,问题(maxv,n)可解,否则无解。

递推算法可以描述为:

for (int i=1; i<=m; i++)
    if (maxv>=x[i]){        //能贴第i张邮票
        if (f[maxv]==0) f[maxv]=f[maxv-x[i]]+1;    //没有贴
        if (f[maxv]>f[maxv-x[i]]+1) f[maxv]=f[maxv-x[i]]+1;    //贴少的
    }

以样例数据为例:

value

f[value]

0

0

1

min{f[1-1]+1}=1

2

min{f[2-1]+1}=2

3

min{f[3-1]+1}=3

4

min{f[4-1]+1,fs[4-4]+1}=1

5

min{f[5-1]+1,fs[5-4]+1}=2

6

min{f[6-1]+1,fs[6-4]+1}=3

7

min{f[7-1]+1,fs[7-4]+1}=4

8

min{f[8-1]+1,fs[8-4]+1}=2

9

min{f[9-1]+1,fs[9-4]+1}=3

10

min{f[10-1]+1,fs[10-4]+1}=4

11

min{f[11-1]+1,fs[11-4]+1}=5  (>4)


代码

#include
using namespace std;
const int M = 105, N = 25600;
int x[M],f[N]={0};    //f[i]  为面额为i所贴邮票最少张数

int main(){
    int n,m,maxv=0;
    cin>>n>>m;
    for (int i=1; i<=m; i++) cin>>x[i];
    while (1){
        maxv++;        //邮票面额
        for (int i=1; i<=m; i++)
            if (maxv>=x[i]){        //能贴第i张邮票
                if (f[maxv]==0) f[maxv]=f[maxv-x[i]]+1;    //没有贴
                if (f[maxv]>f[maxv-x[i]]+1) f[maxv]=f[maxv-x[i]]+1;    //贴少的
            }
        if (f[maxv]==0 || f[maxv]>n){    //达不到面值,或超过了能贴的邮票总数
            cout<<"MAX="<

你可能感兴趣的:(递推)