邮票问题-动态规划

邮票问题

【问题描述】

      给定一个信封,最多只允许粘贴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.:

 输入:

4

2

1

4

 

【样例输出】

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

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

输出:

MAX=10.


解题思路

   本题可以看成是一个集合问题,即求在贴的邮票不多于n张的可满足条件的邮资集.集合问题的关键在于判定元素是否在集合中,对于本题而言,是判断某个邮资是否在贴不多于n张邮票可满足.设当前考虑的邮资值为max,最多允许贴n张邮票,记为(max,n).如果首先贴一张面值为xi的邮票,那么剩下的问题是(max-xi,n-1)的问题.如果(max-xi,n-1)可解,那么(max,n)问题也可解.

       设f[max]表示邮资为max时所需最少的邮票数,f[MAX]=min{f[MAX-w[i]]+1}.当f[max]<=n,问题(max,n)可解,否则无解.找到第一个不能集齐的邮票面值或者是第一个超过n张邮票的面值即可。

代码

#include
#include
#include
using namespace std;
int w[110];//每个邮票的面值
int f[110];
int max;//枚举最大面值
int n,m,t;
const int inf=0x3f3f3f3f;
int main()
{

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&w[i]);
    }
    memset(f,inf,sizeof(f));
    f[0]=0;

    while(1)
    {
      for(max=1;;++max)
      {
        for(int i=1;i<=m;i++)
        {
            if(max>=w[i])//能贴第i张邮票
            {
                if(f[max]>f[max-w[i]]+1)//不贴和贴谁用的张数少
                    f[max]=f[max-w[i]]+1;
            }
        }

        if(f[max]==inf||f[max]>n)//第一个达不到的面值,或者超过了能贴的邮票总数
        {
            printf("%d\n",max-1);
            break;//跳出面值循环
        }
      }

      break;//跳出总循环
    }
    return 0;
}

你可能感兴趣的:(dp)