zoukankan      html  css  js  c++  java
  • 洛谷 P2725 邮票 Stamps 解题报告

    P2725 邮票 Stamps

    题目背景

    给一组 N 枚邮票的面值集合(如,{1 分,3 分})和一个上限 K —— 表示信封上能够贴 K 张邮票。计算从 1 到 M 的最大连续可贴出的邮资。

    题目描述

    例如,假设有 1 分和 3 分的邮票;你最多可以贴 5 张邮票。很容易贴出 1 到 5 分的邮资(用 1 分邮票贴就行了),接下来的邮资也不难:

    6 = 3 + 3 
    7 = 3 + 3 + 1 
    8 = 3 + 3 + 1 + 1 
    9 = 3 + 3 + 3 
    10 = 3 + 3 + 3 + 1 
    11 = 3 + 3 + 3 + 1 + 1 
    12 = 3 + 3 + 3 + 3 
    13 = 3 + 3 + 3 + 3 + 1
    

    然而,使用 5 枚 1 分或者 3 分的邮票根本不可能贴出 14 分的邮资。因此,对于这两种邮票的集合和上限 K=5,答案是 M=13。 [规模最大的一个点的时限是3s]

    小提示:因为14贴不出来,所以最高上限是13而不是15

    输入输出格式

    输入格式:

    第 1 行: 两个整数,K 和 N。K(1 <= K <= 200)是可用的邮票总数。N(1 <= N <= 50)是邮票面值的数量。

    第 2 行 .. 文件末: N 个整数,每行 15 个,列出所有的 N 个邮票的面值,每张邮票的面值不超过 10000。

    输出格式:

    第 1 行:一个整数,从 1 分开始连续的可用集合中不多于 K 张邮票贴出的邮资数。


    这是一个我一开始就想偏了的完全背包。

    一开始:

    #include <cstdio>
    const int N=201;
    const int inf=0x3f3f3f3f;
    int max(int x,int y) {return x>y?x:y;}
    int min(int x,int y) {return x>y?y:x;}
    bool dp[3000010];//表示在第i张时面值k是否ok
    int k,n;//邮票总数,面值数
    int kind[52];
    int m_min=inf,m_max=0;
    int main()
    {
        scanf("%d%d",&k,&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",kind+i);
            m_max=max(kind[i],m_max);
            m_min=min(kind[i],m_min);
        }
        dp[0]=true;
        for(int i=0;i<k;i++)
        {
            int l=m_min*i,r=m_max*i;
            for(int p=r;p>=l;p--)
                if(dp[p])
                    for(int j=1;j<=n;j++)
                        dp[p+kind[j]]=true;
        }
        for(int i=1;i<=m_max*k+1;i++)
        {
            if(!dp[i])
            {
                printf("%d
    ",i-1);
                break;
            }
        }
        return 0;
    }
    
    

    三维的呢。


    完全背包:

    #include <cstdio>
    #include <cstring>
    const int N=201;
    const int inf=0x3f3f3f3f;
    int max(int x,int y) {return x>y?x:y;}
    int min(int x,int y) {return x>y?y:x;}
    int dp[3000010];//表示在组成面值为i时用的最小邮票数
    int k,n,m_max=0;//邮票总数,面值数
    int kind[52];
    int main()
    {
        memset(dp,0x3f,sizeof(dp));
        scanf("%d%d",&k,&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",kind+i);
            m_max=max(m_max,kind[i]);
        }
        dp[0]=0;
        for(int i=1;i<=n;i++)
        {
            int r=m_max*k+1;
            for(int j=0;j<=r;j++)
                dp[j+kind[i]]=min(dp[j+kind[i]],dp[j]+1);
        }
        for(int i=0;;i++)
            if(dp[i]>k)
            {
                printf("%d
    ",i-1);
                break;
            }
        return 0;
    }
    

    其实把(k)放在数组里面最后比,我还真没想到。

    我所能理解的思维导向是从完全背包出发的。

    每种邮票都有无限多张

    注意常数优化,比如(j)的枚举显然并不是最优的


    2018.5.3

  • 相关阅读:
    POJ 1300 Open Door
    POJ 2230 Watchcow
    codevs 1028 花店橱窗布置
    codevs 1021 玛丽卡
    codevs 1519 过路费
    codevs 3287 货车运输
    codevs 3305 水果姐逛水果街二
    codevs 1036 商务旅行
    codevs 4605 LCA
    POJ 1330 Nearest Common Ancestors
  • 原文地址:https://www.cnblogs.com/butterflydew/p/8999762.html
Copyright © 2011-2022 走看看