粉刷匠 (dp)

粉刷匠

题目链接

大致题意:

n个木板,每个木板m个格子,目标的格子只有两种颜色,'0’表示粉色,'1’表示蓝色.

每次只能粉刷一个木板上连续的格子,涂上同一种颜色(每个格子只能被粉刷一次)

求T次粉刷后,粉刷正确颜色的最大格子数

(一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷)说明所有格子都会被粉刷


解题思路:

​ 状态表示: f[i][j] 表示前i个木板,粉刷j次的正确粉刷的最大格子数

​ g[i][j][k]表示第i个木板,粉刷j次,涂了前k个格子的正确粉刷的最大格子数

​ sum[i][j]表示第i个木板前j个格子是蓝色格子的个数

​ sum[i][j]的转移方程很简单,当s[i]=='1’时,sum[i][j]=sum[i][j-1]+1

​ 对g数组来说,就是对第j次粉刷进行讨论,也就是说q(格子数)在区间[j-1,k)内进行转移,(j-1是最小粉刷格子数):

​ j-1次粉刷前q个粉刷正确的格子数+第j次粉刷q到k中蓝色格子和粉色格子数目的最大值

​ sum[i][k] - sum[i][q]是蓝色格子数量,k - q - sum[i][k] + sum[i][q]是粉色格子数量

​ 转移方程: g[i][j][k] = max(g[i][j][k], g[i][j - 1][q] + max(sum[i][k] - sum[i][q], k - q - sum[i][k] + sum[i][q]))

​ f数组就是对第i个木板进行k次粉刷进行讨论

​ 转移方程:f[i][j] = max(f[i][j], f[i - 1][j - k] + g[i][k][m])

​ 最后求一下f[n][i]的最大值即可


AC代码:

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
#define debug(a) cout << #a << " = " << a << endl;
using namespace std;
typedef long long ll;
int n, m, t;
char s[155];
int f[55][2510];		//前i个木板,粉刷j次的正确粉刷的最大格子数
int g[55][2510][55];	//第i个木板,粉刷j次,涂了前k个格子的正确粉刷的最大格子数
int sum[55][55];		//蓝色的格子数

int main(void)
{
	cin >> n >> m >> t;
	for (int i = 1; i <= n; ++i) {
		cin >> s + 1;
		sum[i][0] = 0;
		for (int j = 1; j <= m; ++j) {
			if (s[j] == '1')sum[i][j] = sum[i][j - 1] + 1;
			else sum[i][j] = sum[i][j - 1];
		}
	}

	for (int i = 1; i <= n; ++i) {  //木板
		for (int j = 1; j <= m; ++j) {  //粉刷次数
			for (int k = 1; k <= m; ++k) {	//格子数
				for (int q = j - 1; q < k; ++q) { //格子数
					//判断j-1到k区间蓝色格子多还是粉色格子多
					int tmp = max(sum[i][k] - sum[i][q], k - q - sum[i][k] + sum[i][q]);
					g[i][j][k] = max(g[i][j][k], g[i][j - 1][q] + tmp);

				}
			}
		}
	}

	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= t; ++j) {
			for (int k = 0; k <= min(j, m); ++k) {
				f[i][j] = max(f[i][j], f[i - 1][j - k] + g[i][k][m]);
			}
		}
	}

	int res = 0;
	for (int i = 1; i <= t; ++i)res = max(res, f[n][i]);
	cout << res << endl;
	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值