【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];
}
posted @ 2016-07-13 19:29  sadstone  阅读(49)  评论(0编辑  收藏  举报