状态机的特点:描述的是过程,而不是结果。将一个点扩展成一个过程
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; }
#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; }
#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; }
#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; }