P5662 纪念品

Posted xiaoyezi-wink

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P5662 纪念品相关的知识,希望对你有一定的参考价值。

P5662 纪念品

技术图片

题解

拿到题目想到DP,但是就是不知道咋写

后来证实这是个背包DP(最近整理背包白整了 

 

我们观察这道题目的特殊之处:

技术图片

也就是说,对于手中的物品,我们可以今天买了然后明天早上接着卖出去,当然如果你想一直持有物品的话还可以明天接着再买回来,这样我们在每天进行决策的时候就不用考虑手中持有物品了,因为你手里都是钱,这和第一天情况类似嘛不

然后每一天都是一个新的开始,相似于前一天,然后我们仍然可以按照前一天的做法处理今天,今天也就是你有n个物品,每个物品可以买多个,然后考虑明天早上把它们全部卖出最多可以得到多少钱,然后用明天早上卖出的钱作为新的资本来进行明天的决策

于是我们可以想到完全背包

dp [ i ][ j ][ k ] 到了第 i 天,第 j 个物品,手中还剩下 k 元钱,明天早上把手中的物品全部卖出可以得到的最大利润

dp [ i ][ j ][ k ] = max ( dp [ i ][ j ][ k ] , dp [ i ][ j-1 ][ k - p[ i ][ j ] + p[ i+1 ][ j ] - p[ i ][ j ] )

然后降一维 dp [ k ]

dp [ k ] = max ( dp [ k ] , dp [ k - p[ i ][ j ] ] + p[ i+1 ][ j ] - p[ i ][ j ]  )

我们选取今天的最大利润加上今天的原资本(当然如果今天全赔本肯定就是直接选取原资本作为下一天开始的资本),作为下一天开始的资本

 

注意 dp 数组设置的是利润,所以每次开始新的一天都要清零 dp 数组

 

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>

using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last= ,ch=getchar();
    while(ch<0||ch>9) last=ch,ch=getchar();
    while(ch>=0&&ch<=9) ans=ans*10+ch-0,ch=getchar();
    if(last==-) ans=-ans;
    return ans;
}

int t,n,m,ans=0;
int p[105][105];
int dp[10003];

int main()
{
    t=read();n=read();m=read();
    for(int i=1;i<=t;i++)
        for(int j=1;j<=n;j++)
           p[i][j]=read();
    ans=m;
    for(int i=1;i<=t;i++){
        memset(dp,0,sizeof(dp));
        for(int j=1;j<=n;j++)
            for(int k=p[i][j];k<=m;k++){
                dp[k]=max(dp[k],dp[k-p[i][j]]+p[i+1][j]-p[i][j]);
            }
        for(int j=0;j<=m;j++) ans=max(ans,dp[j]+m);
        m=ans;
    }
    printf("%d
",m);
    return 0;
}

以上是关于P5662 纪念品的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P1094 纪念品分组

一本通网站基础篇完结纪念

纪念一下我的第一个千行代码

DateComponents 似乎没有纪念年份

纪念申请的第一天

纪念品分组