文章目录
A、抛砖引玉 - AcWing 1049. 大盗阿福
本题比较简单,主要起到一个抛砖引玉的作用。
我们可以很容易地想到转移方程:
我们尝试使用状态机模型解决这一类问题。
什么是状态机模型?
状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。
实际上就是我们利用一个类似图论的方法,建图,点表示各各状态,边表示状态转移时要达成的条件,一旦条件成立,就自动转移,所以状态机也是一个自动机。(状态机多运动于游戏等有各种状态转移之中)
例如本题,我们可以把整个模型抽离出两个状态,阿福只有这两个状态:选择当前(最后)店铺,不选择当前店铺。并且分析转移达成的条件,画出边。然后根据这个图非常清晰不重不漏地设计出状态转移方程。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 5000007;
int n, m;
int f[N][2];
int a[N];
int main()
{
int t;
scanf("%d", &t);
while(t -- )
{
scanf("%d", &n);
for(int i = 1; i <= n; ++ i)
scanf("%d", &a[i]);
for(int i = 1; i <= n; ++ i)
{
f[i][0] = max(f[i - 1][0], f[i - 1][1]);
f[i][1] = f[i - 1][0] + a[i];
}
printf("%d\n", max(f[n][0],f[n][1]));
}
return 0;
}
然后我们来看接下来的几个例题:
B、AcWing 1057. 股票买卖 IV
AcWing 1057. 股票买卖 IV
画出状态机模型
这里由于题目要求只能进行k次交易,所以我们设置一个二维数组
然后辅以闫氏DP分析法
注意边界的设置:
- 初始化为0->该状态合法,最开始可以从这里转移过来
- 初始化为
-INF/INF
表示不希望用到它,最开始不能从它转移过来
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 100007;
int n, m;
int w[N];
int f[N][110][2];
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i)
scanf("%d", &w[i]);
memset(f, 0xcf, sizeof f);
for(int i = 0; i <= n; ++ i)
f[i][0][0] = 0;
for(int i = 1; i <= n; ++ i)
for(int k = 1; k <= m; ++ k)
{
f[i][k][0] = max(f[i - 1][k][0], f[i - 1][k][1] + w[i]);
f[i][k][1] = max(f[i - 1][k][1], f[i - 1][k - 1][0] - w[i]);
}
int res;
for(int i = 0; i <= m; ++ i)
res = max(res, f[n][i][0]);
printf("%d\n", res);
return 0;
}
C、AcWing 1058. 股票买卖 V
由于买完股票之后有一天的冷冻期, 所以我们把手里没股票根据题意拆成两种情况,然后分析所有的点与边。
初始化:我们最开始只能从手里无股票两天及以上的这一种情况出发,因为只有这一种可以开始拓展并且符合题意。注意我们必须初始化 f[0][2] = 0; f[0][0] = f[0][1] = -INF;
,因为第一次购买股票是要花钱的,如果不将边界设置为-INF,由于取max操作会导致一直不买。
最后答案在
之中取最大值,因为有可能股票一直下跌不买为最优,这样2就不会转移到1,出口就不再1了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 500007, INF = 0x3f3f3f3f;
int n, m;
int f[N][3];
int w[N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++ i)
scanf("%d", &w[i]);
//0:手里有股票1:手里没股票1天2:手里没股票2天及以上
f[0][2] = 0;
f[0][0] = f[0][1] = -INF;
for(int i = 1; i <= n; ++ i)
{
f[i][0] = max(f[i - 1][2] - w[i], f[i - 1][0]);
f[i][1] = f[i - 1][0] + w[i];
f[i][2] = max(f[i - 1][1], f[i - 1][2]);
}
printf("%d\n", max(f[n][1], f[n][2]));//因为有可能一直不买最优
return 0;
}