P5662 纪念品 - 2019普及T3

P5662 纪念品

https://www.luogu.com.cn/problem/P5662
P5662 纪念品 - 2019普及T3_第1张图片

题意

  • m金币在t天内买卖n个纪念品 。求最多得到多少钱
  • n个纪念品在t天内的价格是不一样的。用数组 w[i]/[j]表示
  • 同时关键——当天可以买卖纪念品。都是同样的价格。

想法

  • 完全背包+贪心
  • **当天可以买卖纪念品。都是同样的价格 ** 这个很关键。
    • 这样可以把第i买,第j天卖的问题转化 为:则等价于在第 i 天买入,第 i+1 天卖出,第 i+1 天再买入, …, 在第 j 天卖出。
    • 因为当天不限制买卖次数,如果明天价格高,大不了我今天卖掉之后再买回来
    • 举个例子:10 20 30 40 表示第i天纪念品的价格。我有100.按之前说:
      • 第一天:全买 ,买10个
      • 第二天:全卖,卖10得 200.发现第三天价格为30,有利可图。重新买回10个。
      • 按照策略。到第五天。
  • 那么好办。问题,假设第 i 天的钱数是 mi,那么第 i+1 天的钱数最多是多少呢?
    • 就变成了完全背包]
      • 背包容量是 mi;
      • 每个股票都是一种物品,体积是第 i天买入的价格,价值在第 i 天买入第 i+1天卖出的收益;
      • 每天可以进行无限次交易,因此每种物品都是可以用无限次;
  • 剪枝:当发现明天的价格低于今年。也就没有差价可赚了的时候。选择不买。
//P5662 纪念品
//https://www.luogu.com.cn/problem/P5662

#include 
using namespace std;
const int maxn = 110,maxm = 10010;
int t,n,m;
//w[i][j]为每天的纪念品价格,dp[i]有钱i,第二天能挣多少(也就是利润)
int w[maxn][maxn],dp[maxm];
int main(){

    cin>>t>>n>>m;
    for(int i=1; i<=t; i++)
    {
        for(int j=1; j<=n; j++)
        {
            cin>>w[i][j];
        }
    }

    //t-1次操作。2天只能操作一次
    for (int i = 1; i <t; ++i) {
        memset(dp,0, sizeof(dp));
        //完全背包模板
        for (int j = 1; j <= n; ++j) {
            if(w[i+1][j] > w[i][j])//剪枝,如果第二天卖这个东西没有差价,就不用卖
            {
                for (int k = w[i][j]; k <= m ; ++k) {
                    dp[k] = max(dp[k],dp[k-w[i][j]]+(w[i+1][j]-w[i][j]));
                }
            }
        }
        m+=dp[m];//资本不断积累,本金+利润
    }
    cout << m;
    return 0;
}

你可能感兴趣的:(贪心,DP)