#写在前面
状态机描述的是一系列有顺序的事件
状态机可以把事件中的各个状态描述清楚
01背包对每个物品只有选与不选,这不是一个连续的过程
状态机描述的是一个过程,不是结果
先有几种状态(几个点),每个状态之间有一些有向边(通道),状态可以通过通道转换,每一次转换相当于走了一步。
当走过k步时,可以有很多种走法。
状态机和状态压缩dp是并列的两个知识点
##大盗啊福
https://www.acwing.com/problem/content/1051/
传统的思考方式
分解对于每个物品(每一步)的状态:
状态机的思考方式:
图论拆点
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100010,inf=0x3f3f3f3f;
int n;
int w[N],f[N][2];
int main(){
int T;cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
f[0][0]=0;f[0][1]=-inf;//入口指向0,虚拟边界不可选
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];
}
printf("%d\n", max(f[n][0], f[n][1]));
}
return 0;
}
##股票买卖4
https://www.acwing.com/problem/content/1059/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100010,M=110;
int n,m;
int w[N];
int f[N][M][2];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d", &w[i]);
memset(f, -0x3f, sizeof f);
for(int i=0;i<=n;i++)f[i][0][0]=0;//如果一次交易都没有进行,手中一定是无货的
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
f[i][j][0]=max(f[i-1][j][0], f[i-1][j][1]+w[i]);
f[i][j][1]=max(f[i-1][j][1], f[i-1][j-1][0]-w[i]);
}
int res=0;
//完整交易表示最终手中无货
for(int i=0;i<=m;i++)res=max(res, f[n][i][0]);
printf("%d\n", res);
return 0;
}
##股票买卖5
https://www.acwing.com/problem/content/1060/
----c++版
//三个状态的
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100210, inf=0x3f3f3f3f;
int n;
int w[N];
int f[N][3];
int main(){
scanf("%d", &n);
for(int i=1;i<=n;i++)scanf("%d", &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]);
}
printf("%d\n", max(f[n][1],f[n][2]));//当一直在亏钱的时候,最优解是一次交易都不做
return 0;
}
##设计密码
https://www.acwing.com/problem/content/1054/
----c++版
#include<iostream>
#include<algorithm>
//kmp和状态机
//kmp的本质是一个j指针在字符串上到处乱跳
//匹配时j永远跳不到子串的末尾,说明没有子串
using namespace std;
const int N=55,mod=1e9+7;
int n,m;
char str[N];
int f[N][N];
int ne[N];//这个要写在外面
#include<cstring>
int main(){
cin>>n>>str+1;
m= strlen(str+1);
for(int i=2,j=0;i<=m;i++){
while (j && str[i] != str[j + 1]) j = ne[j];
if (str[i] == str[j + 1]) j ++ ;
ne[i] = j;
}
f[0][0]=1;
for(int i;i<n;i++)
for(int j=0;j<m;j++)
for(char k='a';k<='z';k++){
int u=j;
while(u&&k!=str[u+1])u=ne[u];
if(k==str[u+1])u++;
if(u<m)f[i+1][u]=(f[i+1][u]+f[i][j])%mod;
}
int res=0;
for(int i=0;i<m;i++)res=(res+f[n][i])%mod;
cout<<res<<endl;
return 0;
}