【COCI2009】着色
Description
Alice是一个奇怪的画家。她想对一副有N*N个像素点组成的画进行着色,N是2的幂(1,2,4,8,16等等)。每个像素点可以着成黑色或白色。
Alice着色方案不是唯一的,她采用以下不确定的规则:
•如果画作只有一个像素点,那可以直接着白色或黑色;
•否则,把画平均分成四块,然后进行以下操作:
(1) 选择一块全部着白色;
(2) 选择一块全部着黑色;
(3) 把剩下的两块当作是独立的画作并采用同样的方法进行着色。
对于每一幅画作,Alice心目中已经有一个蓝图,接下来请你帮她采用上述方法着色,要求选择跟心目中的蓝图差异最小的着色方案,当然要遵循上述的着色规则,两幅图的差异是指对应位置颜色不相同的像素点的个数。
Solution
我们把题目抽象成一颗每个非叶子节点严格有4个节点的有根树,然后对于叶子节点它的贡献为0,然后对于非叶子节点,它的贡献为它四个儿子任选两个染成一黑一白,和另外两个节点的贡献,对12种情况取最小值。
于是求解当然是类似树形dp那样做咯。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 513
#define inf 1000000000
using namespace std;
int f[N*N*4],g[N*N*4];
char s[N];
int map[N][N];
void dfs(int v,int x,int y,int l)
{
if(l==1)
{
g[v]=map[x][y];
f[v]=0;
return;
}
l/=2;
dfs(v*4-2,x,y,l);
dfs(v*4-1,x+l,y,l);
dfs(v*4,x,y+l,l);
dfs(v*4+1,x+l,y+l,l);
g[v]=g[v*4-2]+g[v*4-1]+g[v*4]+g[v*4+1];
fo(i,-2,1)
fo(j,-2,1)
if(i!=j)
{
int t=l*l-g[v*4+i]+g[v*4+j];
fo(k,-2,1)
if(k!=i && k!=j) t+=f[v*4+k];
if(f[v]>t) f[v]=t;
}
}
int main()
{
freopen("4.in","r",stdin);
freopen("4.out","w",stdout);
int n;
cin>>n;
fo(i,1,n)
{
scanf("%s",s+1);
fo(j,1,n)
map[i][j]=s[j]-'0';
}
memset(f,60,sizeof(f));
dfs(1,1,1,n);
cout<<f[1];
}