题意:
给你n,k 长度为n的01串 0代表休息 1代表工作 连续工作每天的cost会++递增 最大可承受cost为k 问你从现在的01串 最小修改几个工作日为休息日使得可以承受。
思路:
记忆化搜索:dfs(位置,翻转次数)
从当前pos向后还是工作日的枚举 找到后比较取min dfs(当前位置的下一位,翻转次数 - 1) + 这一段工作日所需要的cost
当跳出枚举循环时 s[cur] == '0'或cur==n 比较取min dfs(cur,flip) + cost;//为什么是cur不是cur + 1呢 因为这里每次进入dfs时对s[pos]的情况进行了讨论
边界考量:
flip < 0 return inf;
pos == n + 1 return 0;
ans[pos][flip] == -1 return ans[pos][flip];
s[pos] == '0' return dfs(pos + 1,flip);//去下一位
AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,k;
char s[505];
int ans[505][505];
int add(int x){
return x * (x + 1) / 2;
}
int dfs(int pos,int flip){
if(flip < 0) return inf;
if(pos == n + 1) return 0;
if(~ans[pos][flip]) return ans[pos][flip];
if(s[pos] == '0') return dfs(pos + 1,flip);//0
//无特殊情况 让我们开始寻找ans[pos][flip]吧!
ans[pos][flip] = inf;
int cur;
for(cur = pos ; cur <= n && s[cur] == '1' ; cur++){
ans[pos][flip] = min(ans[pos][flip],dfs(cur + 1,flip - 1) + add(cur - pos));
if(!ans[pos][flip]) return 0;
}
ans[pos][flip] = min(ans[pos][flip],dfs(cur,flip) + add(cur - pos));
return ans[pos][flip];
}
int main()
{
memset(ans,-1,sizeof ans);
scanf("%d %d",&n,&k);
scanf("%s",s + 1);
for(int i = 0;i <= n; i++){
if(dfs(1,i) <= k){ //从1开始 变换i个的代价可以承受
printf("%d\n",i);
break;
}
}
}