• Luogu P1021 邮票面值设计


    gate

    这题一看就是没有思路啊_(:3」∠)_

    看起来像是类似货币系统那种背包,但是没有给定物品...

    数据范围并不是很大,大概是O(搜索能过)

    所以用dfs枚举每一种可能的邮票方案,再dp判断当前方案能表示的最大连续面值

    dp:

    枚举用几张邮票?显然不行。数组下标应该是面额,那么...

    设b[i]为第i种邮票,f[j]为表示面额j所需的最少邮票数

    状态转移方程:f[j] = min(f[j],f[j-b[i]]+1);

    然后从1开始枚举,找到第一个f[j+1]>n的,那么j即为能表示的最大面额。

    dfs:

    在递归的过程中,记录并不断用dp更新最大值。

    当枚举邮票数量=k时,判断是否能更新答案,并记录当前的邮票方案。

    剪枝和一些范围的判断很重要!

    首先,枚举邮票的面额时,要保证不重复而且连续。

    范围是[上一张邮票的价值+1,当前能表示的最大面额+1]。

    其次,dp中f[]数组下标的上限是k*所选最后一种邮票面额。

    写memset的话就会TLE(亲测)

    代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    using namespace std;
    
    const int maxn = 1e6+10;
    const int INF = 0x3f3f3f3f;
    int n,k,ans,a[maxn],b[maxn],f[maxn];
    
    int dp(int x) {
        for(int i = 1; i <= b[x]*n; i++)
            f[i] = INF;
        for(int i = 1; i <= x; i++)
            for(int j = b[i]; j <= b[i]*n; j++)
                f[j] = min(f[j],f[j-b[i]]+1);
        for(int i = 0; i <= b[x]*n; i++)
            if(f[i+1] > n)
                return i;
    }
    
    void dfs(int x,int m) {
        if(x > k) {
            if(m <= ans) return;
            ans = m;
            for(int i = 1; i <= k; i++)
                a[i] = b[i];
            return;
        }
        for(int i = b[x-1]; i <= m+1; i++) {
            b[x] = i;
            dfs(x+1,dp(x));
        }
    }
    
    int main() {
        scanf("%d%d",&n,&k);
        dfs(1,0);
        for(int i = 1; i <= k; i++)
            printf("%d ",a[i]);
        printf("
    MAX=%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    HUD 1284 钱币兑换问题
    HUD 1284 钱币兑换问题
    HDU 1283 最简单的计算机
    HDU 1283 最简单的计算机
    商品搜索引擎---推荐系统设计
    Spark机器学习:TF-IDF实例讲解
    【读书笔记】Elasticsearch集成Hadoop最佳实践
    Java面试题集合
    Spring Boot企业微信点餐系统-第一章-课程介绍
    Eclipse下svn的创建分支/合并/切换使用
  • 原文地址:https://www.cnblogs.com/mogeko/p/11778578.html
Copyright © 2020-2023  润新知