Codeforces Round #576 (Div. 1)

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Puzzle harvester

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值