着色
题目
Alice是一个奇怪的画家。她想对一副有N*N个像素点组成的画进行着色,N是2的幂(1,2,4,8,16等等)。每个像素点可以着成黑色或白色。
Alice着色方案不是唯一的,她采用以下不确定的规则:
•如果画作只有一个像素点,那可以直接着白色或黑色;
•否则,把画平均分成四块,然后进行以下操作:
(1) 选择一块全部着白色;
(2) 选择一块全部着黑色;
(3) 把剩下的两块当作是独立的画作并采用同样的方法进行着色。
对于每一幅画作,Alice心目中已经有一个蓝图,接下来请你帮她采用上述方法着色,要求选择跟心目中的蓝图差异最小的着色方案,当然要遵循上述的着色规则,两幅图的差异是指对应位置颜色不相同的像素点的个数。
分析
考虑dp,
定义\(f_{i,j,k,l}(其中0<=k<=log_{2}n)\),表示对于一个矩阵,左上角的点是\((i,j)\),大小为\((2^{k})^{2}\),矩阵类型\(l\)(0表示全为白色的不同原图的个数,1表示全为黑色的不同原图的个数,2表示这个矩阵的最优着色方案)。
显然,答案就是\(f_{1,1,log_{2}n,2}\)
那么转移也显然
\[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}=f_{i,j,k-1,a}+f_{i+2^{k-1},j,k-1,b}+f_{i,j+2^{k-1},k-1,c}+f_{i+2^{k-1},j+2^{k-1},k-1,d}
\]
其中\(a、b、c、d\)中,一个是0,一个是1,剩余的两个是2。
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=515;
using namespace std;
int a[N][N],n,m,f[N][N][11][3],mi[20],z[4][2]
={{1,0},{0,0},{0,1},{1,1}};
int i,j,k;
int solve(int p,int q,int p1,int q1)
{
int t;
p-=1;
p1-=1;
q1-=1;
q-=1;
t=f[i+mi[k-1]*z[p][0]][j+mi[k-1]*z[p][1]][k-1][0]+
f[i+mi[k-1]*z[p1][0]][j+mi[k-1]*z[p1][1]][k-1][1]+
f[i+mi[k-1]*z[q][0]][j+mi[k-1]*z[q][1]][k-1][2]+
f[i+mi[k-1]*z[q1][0]][j+mi[k-1]*z[q1][1]][k-1][2];
if(t<f[i][j][k][2]) f[i][j][k][2]=t;
}
int main()
{
memset(f,43,sizeof(f));
mi[0]=1;
for(i=1;i<=15;i++)
mi[i]=mi[i-1]*2;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
char c;
c=getchar();
while(c!='1' && c!='0')
c=getchar();
a[i][j]=c-48;
f[i][j][0][0]=a[i][j];
f[i][j][0][1]=1-a[i][j];
f[i][j][0][2]=0;
}
int lo=log2(n);
for(k=1;k<=lo;k++)
{
for(i=1;i<=n-mi[k]+1;i++)
for(j=1;j<=n-mi[k]+1;j++)
{
f[i][j][k][0]=f[i][j][k-1][0]+f[i+mi[k-1]][j][k-1][0]+f[i][j+mi[k-1]][k-1][0]+f[i+mi[k-1]][j+mi[k-1]][k-1][0];
f[i][j][k][1]=f[i][j][k-1][1]+f[i+mi[k-1]][j][k-1][1]+f[i][j+mi[k-1]][k-1][1]+f[i+mi[k-1]][j+mi[k-1]][k-1][1];
solve(1,2,3,4);
solve(1,2,4,3);
solve(1,3,2,4);
solve(2,1,3,4);
solve(2,1,4,3);
solve(2,3,1,4);
solve(3,1,2,4);
solve(3,1,4,2);
solve(3,4,1,2);
solve(4,1,2,3);
solve(4,1,3,2);
solve(4,2,1,3);
}
}
printf("%d",f[1][1][lo][2]);
}