算法提高课 第一章 动态规划③ (状态机模型)
作者:互联网
状态机的特点:描述的是过程,而不是结果。将一个点扩展成一个过程
1049. 大盗阿福
DP考虑方式:
用状态机思想考虑:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int f[N][2];//f[i][j]:走了i步,且当前位于不偷 or 偷(状态0 or 1)的所有方案的最大价值
int T,n;
int w[N];
int main()
{
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
memset(f,0,sizeof f);//初始化所有方案的价值为0
f[0][0] = 0,f[0][1] = -0x3f3f3f3f;//一个也不偷的价值为0,f[0][1]为不合法方案,赋值无穷小
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &w[i]);
}
for (int i = 1; i <= n; i ++ )
{
f[i][0] = max(f[i-1][0],f[i-1][1]);//0状态可由前一个物品的0态和1态转移
f[i][1] = f[i-1][0] + w[i]; //1状态只能从前一个物品的0态转移
}
cout<<max(f[n][0],f[n][1])<<endl;//最后一步状态都是合法的,输出价值最大的即可
}
return 0;
}
1057. 股票买卖 IV
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10,K = 110,INF = 0x3f3f3f3f;
int w[N],n,k;
int f[N][K][2];//f[i][j][k]:前i个股票中,恰好完成j次交易,第i个天的状态为k(持仓:1,空仓:0)方案的最大价值
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &w[i]);
}
memset(f,-INF,sizeof f);//求最大值,初始化为负无穷
for (int i = 0; i <= n; i ++ )//前i个股票中,一次交易也没完成,且状态为空仓的价值为0
{
f[i][0][0] = 0;
}
for (int i = 1; i <= n; i ++ )//枚举股票
{
for(int j = 0;j<=k;j++)//枚举交易次数
{
//空仓状态可由持仓和空仓转移而来
f[i][j][0] = f[i-1][j][0];//先继续空仓
if(j) f[i][j][0] = max(f[i][j][0],f[i-1][j-1][1] + w[i]);//可交易时,才根据价值考虑卖出
//注意:只有卖出时才构成一次完整的交易
f[i][j][1] = max(f[i-1][j][0] - w[i],f[i-1][j][1]);//持仓状态可由持仓与空仓转移而来
}
}
int ans = -1;
for (int i = 0; i <= k; i ++ ) ans = max(ans,f[n][i][0]);
//枚举交易次数,题目要求最后必须交易完成,即空仓状态
cout<<ans<<endl;
return 0;
}
1058. 股票买卖 V
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10,INF = 0x3f3f3f3f;
int f[N][3];//f[i][j]:考虑前i个股票,0为持仓,1为空仓的第一天,2为空仓的第2+天
int w[N],n;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &w[i]);
}
memset(f,-INF,sizeof f);
f[0][2] = 0;//注意:入口:无货的第>=2天
for (int i = 1; i <= n; i ++ )
{
f[i][1] = f[i-1][0] + w[i];//持仓只能从空仓转移来
f[i][2] = max(f[i-1][1],f[i-1][2]);//空仓2+天可以从空仓第一天和空仓2+天转移来
f[i][0] = max(f[i-1][0],f[i-1][2] - w[i]);//持仓可以从持仓和空仓2+天转移来
}
cout<<max(f[n][1],f[n][2])<<endl;//出口:无货的第一天 or 无货的第>=2天
return 0;
}
1052. 设计密码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 55,mod = 1e9+7;
int Next[N];
char str[N];
int n;
int f[N][N];
int main()
{
cin>>n>>str+1;
int m = strlen(str+1);
for(int i = 2,j = 0;i<=n;i++)
{
while(j && str[i]!=str[j+1]) j = Next[j];
if(str[i] == str[j+1]) ++j;
Next[i] = j;
}
f[0][0] = 1;
for (int i = 0; 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 = Next[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;
}
标签:std,const,int,scanf,namespace,第一章,状态机,算法,include 来源: https://www.cnblogs.com/zjq182/p/16307482.html