思路:
dp[i][j][k] 表示对于前i天一共工作了j天现在连续工作了k天的最小花费 滚动数组优化掉第一维(不然会MLE)
if(s[i]=='0') 为0只能休息
dp[j][0]=min(dp[j][0],dp[j][k])
if(s[i]=='1')
dp[j][0]=min(dp[j][0],dp[j][k]) 选择休息
dp[j][k]=min(dp[j][k],dp[j-1][k-1]+k) 选择工作
然后发现s[i]==1 选择休息和s[i]==0的转移方程一样
所以
dp[j][0]=min(dp[j][0],dp[j][k]) &&
if(s[i]=='1') dp[j][k]=min(dp[j][k],dp[j-1][k-1]+k)
对于总共工作了j天 j这一层的循环需要倒序
因为是要么做 要么不做 效仿01背包 不然同一天可能会重复计算 最后要找的答案即最小花费≤k的最大的j即可
#include<bits/stdc++.h> using namespace std; int dp[505][505]; char s[505]; int main() { int n,k; cin>>n>>k; cin>>s+1; memset(dp,0x3f,sizeof dp); dp[0][0]=0; for(int i=1;i<=n;i++){ for(int j=i;j;j--){ for(int k=1;k<=j;k++){ dp[j][0]=min(dp[j][0],dp[j][k]);///选择休息 if(s[i]=='1') dp[j][k]=min(dp[j][k],dp[j-1][k-1]+k);///选择工作 } } } for(int i=n;i>=0;i--){ for(int j=0;j<=i;j++){ if(dp[i][j]<=k){ cout<<i<<endl; return 0; } } } }