CF1199F Rectangle Painting 1
一、题意
给定一个 𝑛 × 𝑛 大小的方格图,每个方格一开始是黑色或者白色。每次可以选定一个\(h\times w\)的矩形将其中方格都涂成白色,代价是 \(max(h,w)\) 。求最小代价
输入:
第一行包含一个整数 \(n \;( 1≤n≤50 )\) — 正方形网格的大小。
接下来的 \(n\) 行都包含一个长度为 \(n\) 的字符串,由字符 ". " 和 "#" 组成。如果坐标为 \((i,j)\) 的单元格为黑色,则 i 行第 j 列的字符为'#',否则为白色。
二、分析
选定一个\(h\times w\)的矩形涂成白色,代价是 \(max(h,w)\;\Rightarrow\) 尽可能选正方形去覆盖
将矩形切割,分成形式相同规模更小的子问题,切割一次,染色代价是切割出来的矩阵的边长的最大值,对这个矩阵继续切割,最小代价一定 \(\leq\) 这个矩阵的边长的最大值,可以对 \(x,y\)做切割
三、方法
设 \(f[x_1][y_1][x_2][y_2]\) 表示矩阵 \((x_1,y_1)\) 至 \((x_2,y_2)\) 这个范围染成白色的最小代价
初始代价为 \(max(x_2-x_1,y_2-y_1)\) ,继续切割 x、y,得到的最小代价一定 \(\leq\) 初始值
切割 x :
\[f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],f[x1][y1][k][y2]+f[k+1][y1][x2][y2])
\]
切割 y :
\[f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],f[x1][y1][x2][k]+f[x1][k+1][x2][y2])
\]
#include<bits/stdc++.h>
using namespace std;
int n,f[55][55][55][55];
char a[55][55];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cin>>a[i][j];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]=='.') f[i][j][i][j]=0;
else f[i][j][i][j]=1;
}
}
for(int lx=1;lx<=n;lx++){
for(int ly=1;ly<=n;ly++){
for(int x1=1;x1+lx-1<=n;x1++){
for(int y1=1;y1+ly-1<=n;y1++){
int x2=x1+lx-1;
int y2=y1+ly-1;
if(x1==x2&&y1==y2) continue;
f[x1][y1][x2][y2]=max(x2-x1,y2-y1)+1;
for(int k=x1;k<x2;k++)
f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],f[x1][y1][k][y2]+f[k+1][y1][x2][y2]);
for(int k=y1;k<y2;k++)
f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],f[x1][y1][x2][k]+f[x1][k+1][x2][y2]);
}
}
}
}
cout<<f[1][1][n][n]<<'\n';
return 0;
}

浙公网安备 33010602011771号