JZOJ.1429. 着色

Problem

Description

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

Input

输入第一行包含整数N(1<=N<=512),表示画作的尺寸为N*N,N保证是2的幂。接下来N行每行包含N个0或1,描述Alice心目中的蓝图,0表示白色,1表示黑色。

Output

第一行输出最小的差异是多少。

Sample Input

输入1:
4
0001
0001
0011
1110
输入2:
4
1111
1111
1111
1111
输入3:
8
01010001
10100011
01010111
10101111
01010111
10100011
01010001
10100000

Sample Output

输出1:
1
输出2:
6
输出3:
16

Data Constraint

50%的数据N<=8

Solution

这道题我本来用暴力,但发现有问题TOT。正解直接DP,不过有一点恶心。
我们设 Fi,j,k,l 为以i,j为起点扩大的大小为 2k 的矩阵,l=0表示当前矩阵全白,1全黑,2随便搞搞。那么

Fi,j,k,0,Fi,j,k,1=Σ[0],[1]

Fi,j,k,2 则有12种可能(你们枚举一下就知道了),取最大值就可以了。
(由于这条方程太长,我不打出来了,如果想看的就看看我的标)
最后输出 F1,1,log2(n),2 就可以了。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define N 520
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int a[N][N],f[N][N][12][3],i,j,k,n,mn,ans,_2[12];
char ch;
int main()
{
    freopen("1429_1.in","r",stdin);
    _2[0]=1;
    fo(i,1,12) _2[i]=_2[i-1]*2;
    scanf("%d\n",&n);
    memset(f,127,sizeof(f));
    fo(i,1,n)
    {
        fo(j,1,n) 
        {
            scanf("%c",&ch);
            a[i][j]=ch-48;
            f[i][j][0][0]=a[i][j];
            f[i][j][0][1]=1-a[i][j];
            f[i][j][0][2]=0;
        }
        scanf("\n");
    }
    fo(k,1,log2(n))
        fo(i,1,n-_2[k]+1)
            fo(j,1,n-_2[k]+1)
            {
                f[i][j][k][0]=f[i][j][k-1][0]+f[i+_2[k-1]][j][k-1][0]+f[i][j+_2[k-1]][k-1][0]+f[i+_2[k-1]][j+_2[k-1]][k-1][0];
                f[i][j][k][1]=f[i][j][k-1][1]+f[i+_2[k-1]][j][k-1][1]+f[i][j+_2[k-1]][k-1][1]+f[i+_2[k-1]][j+_2[k-1]][k-1][1];

                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][0]+f[i+_2[k-1]][j][k-1][1]+f[i][j+_2[k-1]][k-1][2]+f[i+_2[k-1]][j+_2[k-1]][k-1][2]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][0]+f[i+_2[k-1]][j][k-1][2]+f[i][j+_2[k-1]][k-1][1]+f[i+_2[k-1]][j+_2[k-1]][k-1][2]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][0]+f[i+_2[k-1]][j][k-1][2]+f[i][j+_2[k-1]][k-1][2]+f[i+_2[k-1]][j+_2[k-1]][k-1][1]);

                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][1]+f[i+_2[k-1]][j][k-1][0]+f[i][j+_2[k-1]][k-1][2]+f[i+_2[k-1]][j+_2[k-1]][k-1][2]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][1]+f[i+_2[k-1]][j][k-1][2]+f[i][j+_2[k-1]][k-1][0]+f[i+_2[k-1]][j+_2[k-1]][k-1][2]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][1]+f[i+_2[k-1]][j][k-1][2]+f[i][j+_2[k-1]][k-1][2]+f[i+_2[k-1]][j+_2[k-1]][k-1][0]);

                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][2]+f[i+_2[k-1]][j][k-1][0]+f[i][j+_2[k-1]][k-1][1]+f[i+_2[k-1]][j+_2[k-1]][k-1][2]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][2]+f[i+_2[k-1]][j][k-1][0]+f[i][j+_2[k-1]][k-1][2]+f[i+_2[k-1]][j+_2[k-1]][k-1][1]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][2]+f[i+_2[k-1]][j][k-1][1]+f[i][j+_2[k-1]][k-1][0]+f[i+_2[k-1]][j+_2[k-1]][k-1][2]);

                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][2]+f[i+_2[k-1]][j][k-1][1]+f[i][j+_2[k-1]][k-1][2]+f[i+_2[k-1]][j+_2[k-1]][k-1][0]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][2]+f[i+_2[k-1]][j][k-1][2]+f[i][j+_2[k-1]][k-1][0]+f[i+_2[k-1]][j+_2[k-1]][k-1][1]);
                f[i][j][k][2]=min(f[i][j][k][2],f[i][j][k-1][2]+f[i+_2[k-1]][j][k-1][2]+f[i][j+_2[k-1]][k-1][1]+f[i+_2[k-1]][j+_2[k-1]][k-1][0]);
            }
    mn=log2(n);
    printf("%d",f[1][1][mn][2]);
}

——2016.7.13

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值