codeforces 1198D Rectangle Painting 1

比赛中写了个假贪心,赛后发现就是个经典的平面区域(棋盘)DP

f[x1][y1][x2][y2]为把这一块变白的最小代价,如果他就是全白的,那么为0,如果只有一个点,那么直接判断然后返回

使用记忆化搜索的形式DP,对于每一次,有一种方案是直接把这一片区域全染白,那么代价是max(y2-y1+1,x2-x1+1)。

另一种方案是把这片区域分成两半然后递归下去找这两半的最小答案加起来。

#include<bits/stdc++.h>
#define maxl 51
using namespace std;
 
int n,ans;
int a[maxl][maxl];
int sum[maxl][maxl];
int f[maxl][maxl][maxl][maxl]; 
char s[maxl][maxl];
struct node
{
	int x,y;
};
queue <node> q;
 
inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		if(s[i][j]=='#')
			a[i][j]=1;
		else
			a[i][j]=0;	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];
}
 
inline int num(int x1,int y1,int x2,int y2)
{
	return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}
 
inline int find(int x1,int y1,int x2,int y2)
{
	if(f[x1][y1][x2][y2]>=0)
		return f[x1][y1][x2][y2];
	if(x1==x2 && y1==y2)
	{
		if(a[x1][y1]==1)
			f[x1][y1][x2][y2]=1;
		else
			f[x1][y1][x2][y2]=0;
		return f[x1][y1][x2][y2];
	}
	if(num(x1,y1,x2,y2)==0)
	{
		f[x1][y1][x2][y2]=0;
		return 0;
	} 
	f[x1][y1][x2][y2]=max(y2-y1+1,x2-x1+1);
	for(int i=x1;i<=x2-1;i++)
		f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],find(x1,y1,i,y2)+find(i+1,y1,x2,y2));
	for(int i=y1;i<=y2-1;i++)
		f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],find(x1,y1,x2,i)+find(x1,i+1,x2,y2));
	return f[x1][y1][x2][y2];
}
 
inline void mainwork()
{
	memset(f,-1,sizeof(f));
	ans=find(1,1,n,n);
}
 
inline void print()
{
	printf("%d",ans);	
}
 
int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值