邮票面值设计

【题目描述】

给定一个信封,最多只允许粘贴N张邮票,询问在给定K(N+K≤40)种邮票的情况下,如何设计邮票的面值,能够得到最大值MAX,使得在1~MAX之间的每一个邮资值都能够得到。

例如,N=3,K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能够得到;

如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能够得到;

可以验证,当N=3,K=2时,7分就是可以得到的连续邮资最大值,所以MAX=7,面值分别为1分、3分。

【输入描述】

输入两个整数N和K。

【输出描述】

第一行输出K个数,表示每种邮票的面值;

第二行输出一个数,表示连续邮资最大值。

【样例输入】

3 2

【样例输出】

1 3

MAX=7

源代码:

#include<cstdio>
#define INF 100000000
int n,k,ans(0),h[40],i[40],f[4000001];
void DP() //DP出此情况的最大连续值,并更新最终结果。
{
    int num(0);
    f[0]=0;
    while (f[num]<=n)
    {
        num++;
        f[num]=INF;
        for (int a=1;a<=k&&num>=h[a];a++)
          if (f[num]>f[num-h[a]]+1)
            f[num]=f[num-h[a]]+1;
    }
    if (num-1>ans)
    {
        ans=num-1;
        for (int a=1;a<=k;a++) //答案数组。
          i[a]=h[a];
    }
}
void DFS(int t) //深搜各种情况。
{
    if (t==k+1) //新情况的构建已经完成,开始检验。
    {
        DP();
        return;
    }
    for (int a=h[t-1]+1;a<=h[t-1]*n+1;a++) //神奇的范围。
    {
        h[t]=a; //小白鼠数组。
        DFS(t+1); //已完成构建新情况的一步。
    }
}
int main() //一足失成千古恨。
{
    scanf("%d%d",&n,&k);
    DFS(1);
    for (int a=1;a<=k;a++)
      printf("%d ",i[a]);
    printf("
MAX=%d",ans);
    return 0;
}

/*
    神妙的范围:
        用样例举例来说:
            如果1想要和N构成合法的一组情况,则N=2,3,4。因为1和2这是毫无疑问的了,三张邮票都是1的面值为3,若想要连续,则应为3+1=4。
        以此类推:
            h[i] ----> [h[i-1]+1(上一步),h[i-1]*n+1]。
*/
原文地址:https://www.cnblogs.com/Ackermann/p/5566866.html