[P5662 CSP-J2019] 纪念品

1. [P5662 CSP-J2019] 纪念品

给定问题是一个关于多天交易商品最大化收益的问题。我们可以用动态规划的五个要素来建模这个问题:

  1. 状态定义(State Definition)

状态变量 dp[k]: 表示手中剩余 k 元现金时,到明天早晨(下一天)都将物品卖出后可以获得的最大现金数。

状态可以用两个部分来表示:

  • i: 当前天数(第几天)。
  • k: 当前拥有的现金数。
  1. 决策变量(Decision Variables)

买或不买:
在每一天,对于每种商品,可以选择买或者不买。

  • 如果选择买:花费一定现金购买某种商品。
  • 如果选择不买:保持现有的现金数不变。
  1. 状态转移方程(State Transition Equation)

price[i][j] 表示第 i 天第 j 件物品的价格。

状态转移方程可以表示为:
d p [ k − price [ i ] [ j ] ] = max ⁡ ( d p [ k − price [ i ] [ j ] ] , d p [ k ] + price [ i + 1 ] [ j ] − price [ i ] [ j ] ) dp[k - \text{price}[i][j]] = \max(dp[k - \text{price}[i][j]], dp[k] + \text{price}[i + 1][j] - \text{price}[i][j]) dp[kprice[i][j]]=max(dp[kprice[i][j]],dp[k]+price[i+1][j]price[i][j])

  • 如果在第 i 天选择买 j 件物品,手中的现金减少 price[i][j] 元。
  • 明天早上将商品卖出后,现金增加 price[i + 1][j] - price[i][j] 元(即差价)。
  1. 边界条件(Boundary Conditions)

初始条件:

  • 第一天下午的钱数 dp[m] 初始化为 m,即早上手里有 m 元现金。
  • 所有其他 dp[k] 初始化为负无穷 (~0x3f) 代表不可达的状态。
  1. 目标函数(Objective Function)

目标: 最大化最后一天结束时的现金数 ans
max ans = max ⁡ ( d p [ j ] ) for  j = 0  to 当前持有现金数 \text{max ans} = \max(dp[j]) \quad \text{for } j = 0 \text{ to 当前持有现金数} max ans=max(dp[j])for j=0 to 当前持有现金数

总结

通过以上动态规划要素的分析,我们可以看到这个问题的本质是一个多阶段决策问题。在每一天的决策过程中,状态变量 dp[k] 记录了每种状态下的最优现金数,通过状态转移方程描述不同选择对状态的影响,最终实现最大化收益的目标。

/*
 * @Description:
 * @Version: 2.0
 * @Author: lbj
 * @Date: 2024-09-02 17:11:09
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2024-09-02 17:43:24
 */
#include <bits/stdc++.h>

using namespace std;

const int Nr = 1e4 + 5;

int a[Nr][Nr];
int dp[Nr];

int main()
{
   int T, N, M;
   cin >> T >> N >> M;

   for (int i = 0; i < T; i++)
   {
      for (int j = 0; j < N; j++)
      {
         cin >> a[i][j];
      }
   }

   int ans = M;

   for (int i = 0; i < T - 1; i++)
   {
      for (int k = 0; k < Nr; k++)
         dp[k] = ~0x3f;

      dp[ans] = ans; // 啥都不买

      for (int j = 0; j < N; j++)
      {
         for (int k = ans; k >= a[i][j]; k--)
         {
            dp[k - a[i][j]] = max(dp[k - a[i][j]], dp[k] + a[i + 1][j] - a[i][j]);
         }
      }

      int ma = 0;
      for (int j = 0; j < ans + 1; j++)
      {
         ma = max(ma, dp[j]);
      }
      ans = ma;
   }
   cout << ans << endl;
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值