状态机
大盗阿福https://www.acwing.com/problem/content/1051/
f[i][0]表示不偷第i家的最大费用
两个状态 偷这家+不偷这家+
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int w[N],f[N][3];
const int inf =1e9;
int main()
{
int t;
cin >> t;
//0未选择店铺 1表示选择
while (t -- ){
int n;cin>>n;
for (int i = 1; i <= n; i ++ ){
cin >> w[i];
}
f[0][0]=0,f[0][1]=0 ;//初始化0为入口 值为0
for (int i = 1; i <= n; i ++ ){
f[i][0]=max(f[i-1][0],f[i-1][1]);//f[i][j]表示第i层是选择了还是没选
f[i][1]=f[i-1][0]+w[i];//只能上层没选择的那种走过来
}
cout << max(f[n][1],f[n][0])<<endl;
}
return 0;
}
股票买卖4 有限制次数的交易 https://www.acwing.com/activity/content/problem/content/1288/
两个状态 手中有股票 手中无股票
f[i][j][0] 第i天 进行第j次交易
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10, inf =0x3f3f3f3f3f;
int w[N],f[N][110][2];
int main()
{
int n,k;cin>>n>>k;
for (int i = 1; i <= n; i ++ ){
cin >> w[i];
}
memset(f, -0x3f, sizeof f);//求最大值 初始化为负无穷 下面再讨论
for (int i = 0; i <= n; i ++ ) f[i][0][0]=0;//一次交易都没有进行所以f为0
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= k; j ++ ){
f[i][j][0]=max(f[i-1][j][1]+w[i],f[i-1][j][0]);
f[i][j][1]=max(f[i-1][j-1][0]-w[i],f[i-1][j][1]);//j次如果交易由j-1得来
}
int res=0;
for (int i = 1; i <= k; i ++ ){//不一定用完交易的次数
res=max(res,f[n][i][0]);
}
cout << res;
return 0;
}
股票交易5 https://www.acwing.com/activity/content/problem/content/1289/
卖出后不能立刻买入 需要冷却一天
多了一个状态 手中无货第一天的自动跳动第二天 设置入口为第二天的状态
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10,inf=0x3f3f3f3f;
int w[N],f[N][3];//0表示手有货 1表示卖出的第一天就是卖出货 2表示卖出的第二天
int n;
int main()
{
cin >> n;
f[0][0]=f[0][1]=-inf;//无限小表示不考虑这个状态,就是不是入口
f[0][2]=0;//这个状态为入口 所以设为0
for (int i = 1; i <= n; i ++ ) cin >> w[i];
for (int i = 1; i <= n; i ++ ){
f[i][0]=max(f[i-1][0],f[i-1][2]-w[i]);
f[i][1]=f[i-1][0]+w[i];
f[i][2]=max(f[i-1][1],f[i-1][2]);
}
cout <<max( f[n][1],f[n][2]);//两个状态都可能成为答案
return 0;
}