浅谈状态机

这东西怎么说呢,我也是一知半解,不能述其所有。
但是我后面要讲的是将状态机这个模型应用到动态规划中去,所以如果是单单如此的应用的话我还是觉得我可以大致讲的明白的(针对小白而言,因为我也是小白哈哈哈)。如果我讲的有哪些地方不正确,或者不清楚的,希望你们可以评论指出,我一定第一时间学习与交流。
状态机这个东西如同其字面所描述的一样,就是将每一个状态,以及状态间转移的所有方式组成一个整体。
而应用到动态方程的就是我们可以通过上一个的状态的所有情况来退出这个当前状态的所有情况,不用推到前几个状态。这样就可以让我们更加容易找到解决的思路。就等于我们将一个原本缠绕在一次的问题,一步一步解开,总比跳步解开容易。这样说也许会让你们有点云里雾里,我也是这样的
那我们后面就用一个具体的例题,来更好的理解这个问题吧。
例题1
题目
阿福是一名经验丰富的大盗。趁着月黑风高,阿福打算今晚洗劫一条街上的店铺。
这条街上一共有 N 家店铺,每家店中都有一些现金。阿福事先调查得知,只有当他同时洗劫了两家相邻的店铺时,街上的报警系统才会启动,然后警察就会蜂拥而至。
作为一向谨慎作案的大盗,阿福不愿意冒着被警察追捕的风险行窃。他想知道,在不惊动警察的情况下,他今晚最多可以得到多少现金?
输入
输入的第一行是一个整数T(T≤50) ,表示一共有T组数据。
接下来的每组数据,第一行是一个整数N(1≤N≤100,000) ,表示一共有N家店铺。第二行是N个被空格分开的正整数,表示每一家店铺中的现金数量。每家店铺中的现金数量均不超过1000。
输出
对于每组数据,输出一行。该行包含一个整数,表示阿福在不惊动警察的情况下可以得到的现金数量。
这题可以用线性DP的方法写,但是也可以用到状态机的方法,所以就用这题来引入状态机这个概念。

因为题目说明不能抢连续的两家店铺,所以我们至少要间隔一间
所以 如果用线性dp的方式写的话,状态转移方程就为

 f[i]=max(f[i-1],f[i-2]+a[i]);

表示抢与不抢当前这个家店铺。
接下来我们试看看如何用状态机来求解这个问题。

在这里插入图片描述图中的含义是若要选择第i个店铺只能从不选择第i-1个店铺这个状态转移而来,而不选择第i个店铺可以从选择第i-1个店铺不选择第i-1个店铺转移而来。这样当前状态的所有情况就可以从上一个状态的所有情况转移而来,只需要考虑上一个状态的所有情况就可以了。
每一次的转移都需要一次步骤,所以一个箭头就代表一次步骤,路径上的权就代表这个步骤的影响。
这就是一个简单的状态机。内含每个状态之间转移的方式。
我们的状态数组为 f [ N ] [ 2 ] f[N][2] f[N][2]:第一维表示第几个店铺,第二维表示状态,抢还是不抢。存储的是每个状态的最大值。
具体代码

#include<iostream>

using namespace std;

const int N=100010,INF=0x3f3f3f3f;
int n,w[N],f[N][2];

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++) cin>>w[i];
		f[0][0]=0,f[0][1]=-INF;
		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]+w[i];
		}
		cout<<max(f[n][1],f[n][0])<<endl;
	}
	return 0;
} 

也许从这题还看不出状态机的作用。
我们接下来再引入一题(源于leetcode)
股票买卖
给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票)
你不能同时参与多笔交易(你必须在再次购买前出售掉持有的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
我们可以根据这个题意来写出一个自动机
在这里插入图片描述
其中有状态012,我们可以开一个状态数组 f [ N ] [ 3 ] f[N][3] f[N][3]第一维表示第几天,第二维表示这一天的状态。存储的是第 i i i天的 j j j状态的最大值。
我们的初始状态是状态2 ,这应该是显而易见的。接下来我们就是将这个自动机转化为代码就可以了。

#include<iostream>

using namespace std;

const int N=100010,INF=0x3f3f3f3f;
int n,w[N],f[N][3];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>w[i];
	
	f[0][0]=f[0][1]=-INF;
	f[0][2]=0;
	
	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])<<endl;
	return 0;
} 

这题应该就可以比较体现状态机的优势了,化繁为简,思路简单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值