2021.06.03邮票面值设计

2021.06.03邮票面值设计

题目描述

给定一个信封,最多只允许粘贴 N 张邮票,计算在给定 K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值 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 分。

输入格式

2 个整数,代表 N,K。

输出格式

输出共 2 行。

第一行输出若干个数字,表示选择的面值,从小到大排序。

第二行,输出 MAX=S,S 表示最大的面值。

样例输入

3 2

样例输出

1 3
MAX=7

思路:dfs+dp

  1. 如果邮票面值固定,可以简单想到通过以下dp求解:
    (1)状态:dp[i]: 可以凑出i的最少有票数。
    (2)转移方程:dp[i] = min{ dp[i], dp[i-val[j]+1 }
    (3)停止条件:dp[i] > n
  2. 但是,本题要求我们设计邮票的面值,所以,可以通过如下方法:
    将dp放入dfs的fit函数中去
  3. 通过模拟样例发现深搜的限定规则:
    如果val[i]表示第i个邮票的面值,可以得到
    val[i+1]∈[ val[i]+1, val[i]*n+1]
    因为每种邮票的面值必须是递增的(否则肯定不能使max最大),并且,如果超过了val[i]*n+1,那么表示的面值就不连续了。

代码

    class Solution{ 
        int k, n;
        int res = 0;
        int[] val = new int[17]; //每种邮票的面值
        int[] ans = new int[17];
        int[] dp = new int[5000];
        void test() {
            Scanner cin = new Scanner(System.in);
            n = cin.nextInt();
            k = cin.nextInt();
            //定义状态 dp[i]: 可以表示i的最少个数 dp[i] = min{ dp[i-val[j]] +1  } 其中j:0~len
            val[1] = 1;
            dfs(1);
            for(int i = 1; i <= k; i++) System.out.print(ans[i]+" ");
            System.out.println();
            System.out.println("MAX="+res);
        }
        //深度搜索,val[i+1]: val[i]+1 ~ val[i]*n+1:  cur表示当前已有个数
        void dfs(int cur) {
            if(cur == k) {
                int i = 0;
                Arrays.fill(dp, Integer.MAX_VALUE);
                dp[0] = 0;
                while(dp[i] <= n) {
                    i++;
                    for(int j = 1; j <= k && i-val[j] >= 0; j++) {
                        dp[i] = Math.min(dp[i], dp[i-val[j]]+1);
                    }
                }
                if(i-1 > res) {
                    ans = Arrays.copyOf(val, val.length);
                    res = i-1;
                }
                return;
            }
            for(int k = val[cur]+1; k <= val[cur]*n+1; k++) {
                val[cur+1] = k; 
                dfs(cur+1);
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值