题意:
给出一个n*m的棋盘,其中某些格子已被染色,现在要对剩余格子黑白染色,且满足:
1、黑白格子分别连通;
2、不存在2*2的单色正方形;
求方案数和任意一种方案;
以黑色为例转移如下:
If 左黑 && 上黑 Then 合并两个连通块
Else If 左白 && 上白 Then 形成新的连通块
Else If 左黑 && 上白 Then 和左边的合并
Else If 左白 && 上黑 Then 和上边的合并
If 左黑 && 上黑 && 左上黑 Then 形成2x2的格子,非法
If 最后一格 && 左白 && 上白 && 左上黑 Then 不连通,非法
If 上白 && 轮廓线上没有和上边相连的格子
If 轮廓线上有白色的格子 Then 不连通, 非法
If 当前格不是最后两格 Then 非法
(因为如果剩下格子有白色,不连通 剩下格子全黑色,必然有2x2的黑色格子)
最后对所有状态判断一下最多只能存在两个连通块
至于输出一个方案的话只要每次记录这个状态是从哪转来的,另外开两个数组记录前驱和当前颜色就好了
const int HashSize = 30007; struct Hash { int chart[HashSize] ,pre[HashSize], sz; int state1[HashSize],state2[HashSize],leftUp[HashSize],col[HashSize]; int stat1[HashSize],stat2[HashSize],lefUp[HashSize]; void clear() { sz = 0; memset(chart, -1, sizeof(chart)); } inline void push(int sta1,int sta2, int leftup, int color,int s1,int s2,int lp) { int x = s1 % HashSize; for (int it = chart[x] ; it != -1 ; it = pre[it]) { if (state1[it] == sta1 &&state2[it] == sta2 && leftUp[it] == leftup&&col[it]==color && stat1[it]==s1 && stat2[it]==s2 &&lefUp[it]==lp) { return ; } } state1[sz] = sta1; state2[sz] = sta2; leftUp[sz]=leftup; col[sz]=color; stat1[sz]=s1; stat2[sz]=s2; lefUp[sz]=lp; pre[sz] = chart[x]; chart[x] = sz ++; } int find(int &sta1,int &sta2, int &leftup) { int x = sta1 % HashSize; for (int it = chart[x] ; it != -1 ; it = pre[it]) { if (stat1[it] == sta1 &&stat2[it] == sta2 && lefUp[it] == leftup) { sta1=state1[it]; sta2=state2[it]; leftup=leftUp[it]; return col[it]; } } } } H[8][8]; struct HashMap { int chart[HashSize] ,pre[HashSize], sz; int state1[HashSize],state2[HashSize],leftUp[HashSize]; long long dp[HashSize]; void clear() { sz = 0; memset(chart, -1, sizeof(chart)); } inline void push(int sta1,int sta2, int leftup, long long val) { int x = sta1 % HashSize; for (int it = chart[x] ; it != -1 ; it = pre[it]) { if (state1[it] == sta1 &&state2[it] == sta2 && leftUp[it] == leftup) { dp[it] += val; return ; } } state1[sz] = sta1; state2[sz] = sta2; leftUp[sz]=leftup; dp[sz] = val; pre[sz] = chart[x]; chart[x] = sz ++; } } HM[2]; int maze[15][15]; int code1[15], code2[15]; int Bin[15]; HashMap *src = HM; HashMap *des = HM + 1; long long ret; inline bool check(int sta) { while(sta) { if((sta&7) > 1) return false; sta >>= 3; } return true; } inline void decode(int *code,int m,int sta) { for (int it = 0 ; it < m ; it ++) { code[it] = sta & 7; sta >>= 3; } } inline int encode(int *code,int m) { int sta = 0; int cnt = 1; memset(Bin , -1 , sizeof(Bin)); for (int it = m - 1 ; it >= 0 ; it --) { if(code[it] == 0) { sta <<= 3; } else { if(Bin[ code[it] ] < 0) Bin[ code[it] ] = cnt ++; code[it] = Bin[ code[it] ]; sta <<= 3; sta |= code[it]; } } return sta; } void getgrid1(int i, int j, int n, int m, int sta1, int sta2, int leftup, long long val) {//白 decode(code1, m, sta1); int up1 = (i == 0) ? 0 : code1[j]; int left1 = (j == 0) ? 0 : code1[j-1]; if(up1 == 0 && left1 == 0) { code1[j] = 7; } else if(up1==0|| left1==0) { code1[j] = up1 + left1; } else if(up1 == left1) { code1[j] = left1; } else { for (int it=0; it<m; it++) { if(code1[it] == up1) code1[it] = left1; } } decode(code2, m, sta2); int up2 = (i == 0) ? 0 : code2[j]; int left2=(i==0)?0:code2[j-1]; if(up2) { int c = 0, cc = 0; for (int it = 0 ; it < m ; it ++) { if(up2 == code2[it]) c ++; if(code2[it]) cc ++; } if(c == 1) {//上黑,且轮廓线上没有与之连通的 if(cc > 1) return; if(!(i==n-1&&j>=m-2)) return; } } code2[j] = 0; if(up2&&left2&&leftup==1)return; if(i==0||j==0||!(up1&&left1&&leftup==1)){ int s1=encode(code1,m), s2=encode(code2,m), lp=up1>0?1:2; des->push(s1, s2, lp, val); H[i][j].push(sta1,sta2,leftup,1,s1,s2,lp); } } void getgrid2(int i, int j, int n, int m, int sta1, int sta2, int leftup, long long val) {//黑 decode(code2, m, sta2); int up2 = (i == 0) ? 0 : code2[j]; int left2 = (j == 0) ? 0 : code2[j-1]; if(up2 == 0 && left2 == 0) { code2[j] = 7; } else if(up2==0|| left2==0) { code2[j] = up2 + left2; } else if(up2 == left2) { code2[j] = left2; } else { for (int it=0; it<m; it++) { if(code2[it] == up2) code2[it] = left2; } } decode(code1, m, sta1); int up1 = (i == 0) ? 0 : code1[j]; int left1=(i==0)?0:code1[j-1]; if(up1) { int c = 0, cc = 0; for (int it = 0 ; it < m ; it ++) { if(up1 == code1[it]) c ++; if(code1[it]) cc ++; } if(c == 1) {//上白,且轮廓线上没有与之连通的 if(cc > 1) return; if(!(i==n-1&&j>=m-2)) return; } } code1[j] = 0; if(up1&&left1&&leftup==2)return; if(i==0||j==0||!(up2&&left2&&leftup==2)){ int s1=encode(code1,m), s2=encode(code2,m), lp=up2>0?2:1; des->push(s1, s2, lp, val); H[i][j].push(sta1,sta2,leftup,2,s1,s2,lp); } } void PlugDP(int n, int m) { src->clear(); src->push(0, 0, 1, 1); ret = 0; for ( int i = 0 ; i < n ; i ++ ) { for ( int j = 0 ; j < m ; j ++ ) { des->clear(); for ( int k = 0 ; k < src->sz ; k ++ ) {//1白2黑 if(maze[i][j]!=2) getgrid1(i, j, n, m, src->state1[k], src->state2[k], src->leftUp[k], src->dp[k]); if(maze[i][j]!=1) getgrid2(i, j, n, m, src->state1[k], src->state2[k], src->leftUp[k], src->dp[k]); } swap(src, des); } } int t; for (int i = 0 ; i < src->sz ; i ++ ) { if ( check(src->state1[i])&&check(src->state2[i]) ) {t=i;ret += src->dp[i];} } cout<<ret<<endl; if(ret){ int sta1=src->state1[t],sta2=src->state2[t],leftup=src->leftUp[t]; string s[8]; for(int i=n-1;i>=0;i--){ s[i]=""; int col; for(int j=m-1;j>=0;j--){ col=H[i][j].find(sta1,sta2,leftup); if(col==1)s[i].insert(0,"o"); else s[i]=s[i].insert(0,"#"); } } for(int i=0;i<n;i++) cout<<s[i]<<endl; } cout<<endl; } int main() { int T,n,m; string str="12345678910"; cin>>T; T++; while(T--){ cin>>n>>m; for(int i=0;i<n;i++){ cin>>str; for(int j=0;j<m;j++){ if(str[j]=='o')maze[i][j]=1;//1白2黑 else if(str[j]=='#')maze[i][j]=2; else maze[i][j]=0; H[i][j].clear(); } } PlugDP(n,m); } return 0; }