1. 程式人生 > >洛谷 P2725 解題報告

洛谷 P2725 解題報告

tdi int 計算 main 枚舉 str 接下來 true mem

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\n",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\n",i-1);
            break;
        }
    return 0;
}

其實把\(k\)放在數組裏面最後比,我還真沒想到。

我所能理解的思維導向是從完全背包出發的。

每種郵票都有無限多張

註意常數優化,比如\(j\)的枚舉顯然並不是最優的


2018.5.3

洛谷 P2725 解題報告