Gym-101875E Loppinha, the boy who likes sopinha

题意:

给你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;
		}
	}
}
发布了31 篇原创文章 · 获赞 5 · 访问量 1371

猜你喜欢

转载自blog.csdn.net/qq_43685900/article/details/102756777