【JZOJ1429】着色

description

Alice是一个奇怪的画家。她想对一副有N*N个像素点组成的画进行着色,N是2的幂(1,2,4,8,16等等)。每个像素点可以着成黑色或白色。
  Alice着色方案不是唯一的,她采用以下不确定的规则:
  •如果画作只有一个像素点,那可以直接着白色或黑色;
  •否则,把画平均分成四块,然后进行以下操作:
  (1) 选择一块全部着白色;
  (2) 选择一块全部着黑色;
  (3) 把剩下的两块当作是独立的画作并采用同样的方法进行着色。
  对于每一幅画作,Alice心目中已经有一个蓝图,接下来请你帮她采用上述方法着色,要求选择跟心目中的蓝图差异最小的着色方案,当然要遵循上述的着色规则,两幅图的差异是指对应位置颜色不相同的像素点的个数。


analysis

  • 树形DPDPDP考场dfs没调对

  • 把大正方形看成一个树点,四个小正方形看成四个儿子节点

  • f[i]f[i]f[i]表示当前矩阵的最小代价,先遍历整棵树

  • 叶子结点肯定是000,向上回溯,记录每个矩阵中白点或黑点的个数

  • 如果该儿子染白,代价就是黑点的个数;该儿子染黑,代价就是白点的个数

  • 一种情况即为两个小矩阵染黑染白的代价加上剩下两个矩阵各自的fff

  • 每个非叶节点共有十二种情况,枚举一遍,取最小值


code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 515
#define ll long long
#define fo(i,a,b) for (ll i=a;i<=b;++i)
#define fd(i,a,b) for (ll i=a;i>=b;--i)

using namespace std;

ll a[MAXN][MAXN];
ll f[MAXN*MAXN*4],g[MAXN*MAXN*4];
ll n;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline void dfs(ll t,ll x,ll y,ll z)
{
	if (z==1)
	{
		f[t]=0,g[t]=a[x][y];
		return;
	}
	dfs(t*4-2,x,y,z/2),dfs(t*4-1,x,y+z/2,z/2),
	dfs(t*4,x+z/2,y,z/2),dfs(t*4+1,x+z/2,y+z/2,z/2);
	g[t]=g[t*4-2]+g[t*4-1]+g[t*4]+g[t*4+1];
	fo(i,-2,1)fo(j,-2,1)if (i!=j)
	{
		ll tmp=z*z/4-g[t*4+i]/*white*/+g[t*4+j];/*black*/
		fo(k,-2,1)if (k!=i && k!=j)tmp+=f[t*4+k];
		f[t]=min(f[t],tmp);
	}
}
int main()
{
	//freopen("T3.in","r",stdin);
	n=read(),scanf("\n");
	fo(i,1,n)
	{
		fo(j,1,n)a[i][j]=getchar()-'0';
		scanf("\n");
	}
	memset(f,127,sizeof(f)),dfs(1,1,1,n);
	printf("%lld\n",f[1]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值