状态机模型
定义
动态规划中的算法状态机模型是一种用于描述算法执行过程中状态变化的模型。它由状态、事件、动作和转移组成。状态表示算法在某个时刻所处的情况,事件是导致状态发生变化的原因,动作是在状态变化时执行的操作,转移则定义了状态之间的转换关系。
注意事项
- 确保状态和事件的定义清晰明确,避免歧义。
- 考虑所有可能的状态和事件,以确保模型的完整性。
- 对状态转移进行仔细设计,确保其正确性和合理性。
- 在实现算法时,要正确处理状态的变化和相应的动作。
算法状态机模型可以帮助我们更好地理解和设计复杂的算法,尤其适用于具有多个状态和复杂控制流程的问题。通过清晰地描述状态和状态之间的转换,可以提高算法的可读性、可维护性和正确性。
解题思路
- 定义状态:确定算法可能处于的不同状态。
- 确定事件:识别导致状态变化的事件。
- 定义动作:描述在每个状态下执行的操作。
- 绘制状态机图:使用图形表示状态、事件、动作和转移之间的关系。
- 实现算法:根据状态机图编写代码来实现算法。
保证状态的合理性与正确性
- 清晰定义状态和事件:明确每个状态的含义和可能的事件,确保状态和事件的定义准确无误。
- 绘制状态机图:通过图形化的方式展示状态机模型,有助于直观地理解状态转移关系,发现潜在的问题。
- 设计合理的状态转移规则:仔细考虑每个状态下可能的事件和相应的状态转移,确保转移规则符合实际情况和业务需求。
- 进行边界情况和异常情况的处理:考虑状态机在边界情况和异常情况下的行为,确保它能够正确处理这些情况,避免出现错误的状态转移。
- 验证和测试:使用测试用例对状态机进行验证和测试,确保在各种情况下状态转移的正确性和合理性。
- 审查和评审:让其他团队成员对状态机模型进行审查和评审,他们可能会发现一些潜在的问题或提出改进建议。
- 持续改进:在使用状态机的过程中,不断总结经验教训,发现问题并及时进行改进。
- 参考已有模型:可以参考已有的类似状态机模型,借鉴其设计经验和最佳实践。
- 使用工具支持:有些工具可以帮助设计和验证状态机模型,例如状态机图绘制工具和模型验证工具。
- 考虑并发和异步情况:如果状态机涉及并发或异步操作,需要特别注意状态转移的正确性和合理性,避免竞态条件和死锁等问题。
AcWing 1057. 股票买卖 IV
题目描述
1057. 股票买卖 IV - AcWing题库
运行代码
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 110, INF = 0x3f3f3f3f;
int n, m;
int f[M][2];
int main()
{
cin >> n >> m;
f[0][0] = 0;
for (int i = 1; i <= n; i ++ )
{
int w;
cin >> w;
for (int j = 1; j <= m; j ++ )
{
if(i == 1) f[j][1] = -w;
else
{
f[j][0] = max(f[j][0], f[j][1] + w);
f[j][1] = max(f[j][1], f[j - 1][0] - w);
}
}
}
cout << f[m][0] << endl;
return 0;
}
代码思路
- 定义了一些常量和变量,包括最大数量
M
,无穷大表示INF
,以及问题中的n
(天数)和m
(最多交易次数)。 f[M][2]
这个二维数组用于存储状态,f[j][0]
表示在进行了j
次交易且当前不持有股票时的最大利润,f[j][1]
表示在进行了j
次交易且当前持有股票时的最大利润。- 在输入天数和交易次数后,开始遍历每一天。
- 对于每一天,如果是第一天,直接初始化
f[j][1]
为-w
(即买入股票的成本)。 - 对于不是第一天的情况,通过两个状态转移方程来更新状态:
f[j][0] = max(f[j][0], f[j][1] + w)
表示当前不持有股票的最大利润可能来自于保持之前的状态或者卖出当前持有的股票;f[j][1] = max(f[j][1], f[j - 1][0] - w)
表示当前持有股票的最大利润可能来自于保持之前的持有状态或者买入新的股票(用之前不持有股票且少一次交易的利润减去买入成本)。 - 最后输出
f[m][0]
,即进行了m
次交易且最终不持有股票时的最大利润。
其它代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010, M = 110;
int n, k;
int a[N], f[N][M][2];
int main()
{
memset(f, -0x3f, sizeof f);
cin >> n >> k;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(int i = 0; i <= n; i ++ ) f[i][0][0] = 0;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= k; j ++ )
{
f[i][j][0] = max(f[i - 1][j][0], f[i - 1][j][1] + a[i]);
f[i][j][1] = max(f[i - 1][j][1], f[i - 1][j - 1][0] - a[i]);
}
int res = 0;
for(int i = 0; i <= k; i ++ ) res = max(res, f[n][i][0]);
cout << res << endl;
}
代码思路
- 定义了一些常量,包括数组最大长度
N
和最大交易次数M
。 - 输入股票价格序列的长度
n
和最大交易次数k
,并读取股票价格数组a[N]
。 - 通过
memset
初始化三维数组f[N][M][2]
的所有值为较小值。 - 特别地,将
f[i][0][0]
(即没有进行任何交易且不持有股票时)初始化为 0。 - 然后通过三层循环进行动态规划计算:
- 对于每一个位置
i
和交易次数j
,计算f[i][j][0]
(当前不持有股票的最大利润),它可以是上一步不持有股票的最大利润,或者是上一步持有股票并在当前卖出的利润(加上当前价格)。 - 计算
f[i][j][1]
(当前持有股票的最大利润),它可以是上一步持有股票的利润,或者是上一步没有持有股票且少一次交易然后在当前买入的利润(减去当前价格)。
- 对于每一个位置
- 最后在所有结束状态中(即
n
位置和不同交易次数的不持有股票状态)找出最大利润值并输出。