题目大意
一个矩形,每个格点初始时是黑或白。
两方轮流操作,每次将一个白格点染黑,如果因为这次操作每将一个1*1正方形的四个格点都变黑可以获得该正方形的权值,一次操作使得获得权值不为0那么可以继续操作。
求两者采用最优策略下先手得到的分数与后手得到的分数的差。
模拟
列个状压DP然后就是模拟题意,注意使用位运算优化常数。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct dong{
int a,b;
};
int i,j,k,l,t,n,m,tot;
int two[25];
int id[25][25];
dong pic[25];
dong f[2][1<<21];
int w[25];
bool bz[2][1<<21];
void dfs(int x,int y){
if (y==two[n*m]-1) return;
if (bz[x][y]) return;
bz[x][y]=1;
int i,j=0,k=0,t;
if (x) k=-1;else j=-1;
fo(i,0,n*m-1)
if ((two[i]&y)==0){
t=0;
if (i%m>0&&i>m-1&&(two[i-1]&y)!=0&&(two[i-m]&y)!=0&&(two[i-m-1]&y)!=0) t+=w[i-m-1];
if (i%m<m-1&&i>m-1&&(two[i+1]&y)!=0&&(two[i-m]&y)!=0&&(two[i-m+1]&y)!=0) t+=w[i-m];
if (i%m<m-1&&i<(n-1)*m&&(two[i+1]&y)!=0&&(two[i+m]&y)!=0&&(two[i+m+1]&y)!=0) t+=w[i];
if (i%m>0&&i<(n-1)*m&&(two[i-1]&y)!=0&&(two[i+m]&y)!=0&&(two[i+m-1]&y)!=0) t+=w[i-1];
if (t){
dfs(x,y+two[i]);
if (x){
if (f[x][y+two[i]].b+t>k) k=f[x][y+two[i]].b+t,j=f[x][y+two[i]].a;
}
else{
if (f[x][y+two[i]].a+t>j) j=f[x][y+two[i]].a+t,k=f[x][y+two[i]].b;
}
}
else{
dfs(1-x,y+two[i]);
if (x){
if (f[1-x][y+two[i]].b>k) k=f[1-x][y+two[i]].b,j=f[1-x][y+two[i]].a;
}
else{
if (f[1-x][y+two[i]].a>j) j=f[1-x][y+two[i]].a,k=f[1-x][y+two[i]].b;
}
}
}
f[x][y].a=j;
f[x][y].b=k;
}
int main(){
//freopen("coloring.in","r",stdin);freopen("coloring.out","w",stdout);
two[0]=1;
fo(i,1,21) two[i]=two[i-1]*2;
scanf("%d%d",&n,&m);
t=0;
fo(i,1,n){
fo(j,1,m){
id[i][j]=tot++;
scanf("%d",&k);
if (k) t=t+two[tot-1];
}
}
fo(i,1,n-1)
fo(j,1,m-1)
scanf("%d",&w[id[i][j]]);
dfs(0,t);
printf("%d\n",f[0][t].a-f[0][t].b);
//fclose(stdin);fclose(stdout);
return 0;
}