codeforces-1199F(记忆化DP)-Rectangle Painting 1

CF-1199E-Rectangle Painting 1

题目链接: codeforces-1199F.

题目描述

           \;\;\;\;\; 给出一个 n ⋅ n n\cdot n nn网格,每个格子是黑色或白色。
           \;\;\;\;\; 现在有一种染色方法,每次可以选择一个矩形区域 w × h w \times h w×h,将其中的所有格子染成白色,代价为 m a x ( w , h ) max(w,h) max(w,h).

           \;\;\;\;\; 问:将所有格子染成白色的最小代价。(格子可被重复染色)
           \;\;\;\;\; 1 ≤ n ≤ 50 1\leq n \leq 50 1n50.

思路

       \;\;\; 这长得像个dp,但我没想到是这样的dp.
       \;\;\; f [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] f[x1][y1][x2][y2] f[x1][y1][x2][y2] 表示将矩形区域 ( x 1 , y 1 ) → ( x 2 , y 2 ) (x1,y1) \rightarrow (x2,y2) (x1,y1)(x2,y2) (左上角,右下角)染成白色的最小代价。每次只要将矩形划分为两部分的和求解即可,
       \;\;\; 初始化: f [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] = m a x ( x 2 − x 1 + 1 ,    y 2 − y 1 + 1 ) f[x1][y1][x2][y2]=max(x2-x1+1, \; y2-y1+1) f[x1][y1][x2][y2]=max(x2x1+1,y2y1+1).
       \;\;\; 转移方程:
&ThickSpace;&ThickSpace;&ThickSpace;&ThickSpace;&ThickSpace; \;\;\;\;\; 横向分割: f [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] = m i n { f [ x 1 ] [ y 1 ] [ i ] [ y 2 ] + f [ i + 1 ] [ y 1 ] [ x 2 ] [ y 2 ] } f[x1][y1][x2][y2]=min\left \{ f[x1][y1][i][y2] + f[i+1][y1][x2][y2] \right \} f[x1][y1][x2][y2]=min{f[x1][y1][i][y2]+f[i+1][y1][x2][y2]} ( x 1 ≤ i &lt; x 2 ) (x1 \leq i &lt; x2) (x1i<x2).
&ThickSpace;&ThickSpace;&ThickSpace;&ThickSpace;&ThickSpace; \;\;\;\;\; 纵向分割: f [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] = m i n { f [ x 1 ] [ y 1 ] [ x 2 ] [ j ] + f [ x 1 ] [ j + 1 ] [ x 2 ] [ y 2 ] } f[x1][y1][x2][y2]=min\left \{ f[x1][y1][x2][j] + f[x1][j+1][x2][y2] \right \} f[x1][y1][x2][y2]=min{f[x1][y1][x2][j]+f[x1][j+1][x2][y2]} ( y 1 ≤ j &lt; y 2 ) (y1 \leq j &lt; y2) (y1j<y2).
&ThickSpace;&ThickSpace;&ThickSpace; \;\;\; 时间复杂度: O ( n 4 ) O(n^{4}) O(n4)

代码


#include <bits/stdc++.h>

using namespace std;

const int MAXN = 55;
int n;
char s[MAXN][MAXN];
int f[MAXN][MAXN][MAXN][MAXN];

int find(int x1, int y1, int x2, int y2) {
	if(f[x1][y1][x2][y2] != -1) return f[x1][y1][x2][y2];
	if(x1 == x2 && y1 == y2) {
		if(s[x1][y1] == '#') f[x1][y1][x2][y2] = 1;
		else f[x1][y1][x2][y2] = 0;	
		return f[x1][y1][x2][y2];
	}
	f[x1][y1][x2][y2] = max(x2 - x1 + 1, y2 - y1 + 1);
	for(int i = x1; i < x2; i++) { // 横着切 
		if(f[x1][y1][i][y2] == -1) find(x1, y1, i, y2);
		if(f[i+1][y1][x2][y2] == -1) find(i+1, y1, x2, y2);
		f[x1][y1][x2][y2] = min(f[x1][y1][x2][y2], f[x1][y1][i][y2] + f[i+1][y1][x2][y2]);
		
	}
	for(int j = y1; j < y2; j++) { // 竖着切 
		if(f[x1][y1][x2][j] == -1) find(x1, y1, x2, j);
		if(f[x1][j+1][x2][y2] == -1) find(x1, j+1, x2, y2);		
		f[x1][y1][x2][y2] = min(f[x1][y1][x2][y2], f[x1][y1][x2][j] + f[x1][j+1][x2][y2]);
	}	
//	cout << x1 << " " << y1 << " " << x2 << " " << y2 << " " << f[x1][y1][x2][y2] << "   last"<< endl;
	return f[x1][y1][x2][y2];
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%s",s[i]+1);
	}
	memset(f, -1, sizeof(f));
	printf("%d\n", find(1,1,n,n));
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值