D. Rectangle Painting 1
题意:
有一个大小为n *n(1<=n<=50)的网格,其中一些是黑色的(’#’),其余的都是白色的(’.’)。你每次操作可以任意选择一个大小为h *w的矩形并把它全部都染成白色,花费为max(h,w)。现在你想要把所有的格子都染成白色,请求出最小花费。
分析:
如果一个矩形可以分割当且仅当存在一行或者一列全为白色。这样我们就可以DP了,设
f(x1,y1,x2,y2)表示矩阵左上角(x1,y1),右下角(x2,y2)染成白色的代价。
状态转移方程:
将矩阵从左上角(x1,y1)到右下角(x2,y2)拆分成:矩阵1(从左上角(x1,y2)到右下角(i,y2))和矩阵2(从左上角(i+1,y2)到右下角(x2,y2)),(x1<=i<=x2)。
dp[x1][y1][x2][y2]=min(dp[x1][y1][x2][y2],dfs(x1,y1,i,y2)+dfs(i+1,y1,x2,y2));
将矩阵从左上角(x1,y1)到右下角(x2,y2)拆分成:矩阵1(从左上角(x1,y2)到右下角(x2,i))和矩阵2(从左上角(x1,i+1)到右下角(x2,y2)),(y1<=i<=y2)。
dp[x1][y1][x2][y2]=min(dp[x1][y1][x2][y2],dfs(x1,y1,x2,i)+dfs(x1,i+1,x2,y2));
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=50+5;
int dp[MAXN][MAXN][MAXN][MAXN]; //dp[x1][y1][x2][y2]表示矩阵左上角(x1,y1),右下角(x2,y2)的一个最小花费
char str[MAXN][MAXN];
int dfs(int x1,int y1,int x2,int y2)
{
if(x1==x2&&y1==y2) //一个格子
{
if(str[x1][y1]=='#')return 1; //如果等于黑色格子那么花费为1
else return 0; //否则为0
}
if(dp[x1][y1][x2][y2]!=-1)return dp[x1][y1][x2][y2]; //如果搜过返回
dp[x1][y1][x2][y2]=max(x2-x1+1,y2-y1+1); //取一个最大值,作为当前花费
for(int i=x1;i<=x2;i++)
{
dp[x1][y1][x2][y2]=min(dp[x1][y1][x2][y2],dfs(x1,y1,i,y2)+dfs(i+1,y1,x2,y2));
}
for(int i=y1;i<=y2;i++)
{
dp[x1][y1][x2][y2]=min(dp[x1][y1][x2][y2],dfs(x1,y1,x2,i)+dfs(x1,i+1,x2,y2));
}
return dp[x1][y1][x2][y2];
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%s",str[i]+1);
}
memset(dp,-1,sizeof(dp));
printf("%d\n",dfs(1,1,n,n));
}
return 0;
}