比赛中写了个假贪心,赛后发现就是个经典的平面区域(棋盘)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;
}