【蓝桥杯】试题 算法提高 邮票面值设计【c++】

题目:

问题描述

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

  例如,N=3,K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能得到(当然还有8分、9分和12分);如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3,K=2时,7分就是可以得到的连续的邮资最大值,所以MAX=7,面值分别为1分、3分。

输入格式

  一行,两个数N、K

输出格式

  两行,第一行升序输出设计的邮票面值,第二行输出“MAX=xx”(不含引号),其中xx为所求的能得到的连续邮资最大值。

样例输入

3 2

样例输出

1 3
MAX=7

思路:

1.用dfs搜邮票面值的组合

子树的方向:

dfs(第i个邮票,第i个邮票的面值){

        dfs(第i+1个邮票,第i+1个邮票的面值)

}

 边界:

for (int j = (i_value+1); j <= (now_value + 1); ++j){
    //1.下一张邮票面值一定比这张大
    //2.前i张邮票能凑成的连续最大邮资为now_value
    //则第i+1张邮票价值不超过now_value+1
    //否则now_value+1这个面值就凑不了了
    dfs(i + 1, j);
}

2.用dp确定每种邮票组合的连续最大邮资

       

//递推:其中1<=j<=k
f[i] = min(f[i], f[i - val[j]] + 1)

完整代码:

#include<bits/stdc++.h>

using namespace std;

int n, k, ans = 0;
int val[15];//面值表,长度k,from 1
int result[15];//最大面值的表

int dp(int len) {
    //由当前面值表得到连续最大面值
    //表长自定
    int f[200] = {0};//f[面值]=最少张数
    f[0] = 0;
    f[1] = 1;
    int this_max = 1;
    for (int i = 2; i <= (val[len] * n); ++i) {
        //面值最大值为
        ++this_max;
        f[i] = 100000;
        for (int j = 1; j <= len; ++j) {
            if ((i - val[j]) < 0) {
                break;
            }
            f[i] = min(f[i], f[i - val[j]] + 1);
        }
        if (f[i] > n) {
            --this_max;
            break;
        }
    }

    return this_max;
}

void dfs(int i, int i_value) {
    //第i个,面值i_value
    if (i > k) {
        return;
    }

    //更新
    val[i] = i_value;
    int now_value = dp(i);
    if (now_value > ans) {
        for (int j = 1; j <= k; ++j) {
            result[j] = val[j];

        }
        ans = now_value;
    }

    //子树
    for (int j = (i_value + 1); j <= (now_value + 1); ++j) {
        dfs(i + 1, j);
    }
}

int main() {

    cin >> n >> k;
    dfs(1, 1);
    for (int i = 1; i <= k; ++i) {
        cout << result[i] << ' ';
    }
    cout << endl << "MAX=" << ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值