1. [P5662 CSP-J2019] 纪念品
给定问题是一个关于多天交易商品最大化收益的问题。我们可以用动态规划的五个要素来建模这个问题:
- 状态定义(State Definition)
状态变量
dp[k]
: 表示手中剩余k
元现金时,到明天早晨(下一天)都将物品卖出后可以获得的最大现金数。状态可以用两个部分来表示:
i
: 当前天数(第几天)。k
: 当前拥有的现金数。
- 决策变量(Decision Variables)
买或不买
:
在每一天,对于每种商品,可以选择买或者不买。
- 如果选择买:花费一定现金购买某种商品。
- 如果选择不买:保持现有的现金数不变。
- 状态转移方程(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[k−price[i][j]]=max(dp[k−price[i][j]],dp[k]+price[i+1][j]−price[i][j])
- 如果在第
i
天选择买j
件物品,手中的现金减少price[i][j]
元。- 明天早上将商品卖出后,现金增加
price[i + 1][j] - price[i][j]
元(即差价)。
- 边界条件(Boundary Conditions)
初始条件:
- 第一天下午的钱数
dp[m]
初始化为m
,即早上手里有m
元现金。- 所有其他
dp[k]
初始化为负无穷 (~0x3f
) 代表不可达的状态。
- 目标函数(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;
}