玩诈欺的小杉——异或优化的状压dp

玩诈欺的小杉

是这样的,在小杉的面前有一个N行M列的棋盘,棋盘上有N*M个有黑白棋的棋子(一面为黑,一面为白),一开始都是白面朝上。
  小杉可以对任意一个格子进行至多一次的操作(最多进行N*M个操作),该操作使得与该格同列的上下各2个格子以及与该格同行的左右各1个格子以及该格子本身翻面。
  例如,对于一个5*5的棋盘,仅对第三行第三列的格子进行该操作,得到如下棋盘(0表示白面向上,1表示黑面向上)。

  00100
  00100
  01110
  00100
  00100

  对一个棋盘进行适当的操作,使得初始棋盘(都是白面朝上)变成已给出的目标棋盘的操作集合称作一个解法。
  小杉的任务是对给出的目标棋盘求出所有解法的总数。

 

每组测试数据的第一行有3个正整数,分别是N和M和T(1<=N,M<=20,1<=T<=5)
  接下来T个目标棋盘,每个目标棋盘N行,每行M个整数之前没有空格且非0即1,表示目标棋盘(0表示白面朝上,1表示黑面朝上)
两个目标棋盘之间有一个空行。
  特别地,对于30%的数据,有1<=N,M<=15

 

对每组数据输出T行,每行一个整数,表示能使初始棋盘达到目标棋盘的解法总数

输入:

4 4 2

0010

0010

0111

0010

 

0010

0110

0111

0010

输出:

1

1

【样例解释】
对于输入的数据,两个目标棋盘各有一种解法
1:
0000
0000
0010
0000
2:
1011
1101
0111
1011
其中1表示对该格进行操作,0表示不操作

分析:

这种类似棋盘的东西其实很容易让我们想到状压,对比两个方向的状压,我们会倾向于选择一列一列地推过去,因为这样问题更加简单。所以我们可以很轻松地和普通的状压一样打出此题,但是显然的时间复杂度O(2nNMT)会超时,此时我们应试着研究转移过程。我们会发现,0与1的翻转其实就是异或的过程,在上述做法中我们一一枚举了每一列的各个数。现在我们来考虑转化为异或来将复杂度缩去一个N,对于"十字架"两端可以直接异或,而对于中间那一长条我们要稍微处理一下,将这一串进行移动再累次异或即可。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
#define R register
#define ld long double
#define debug printf("zxt\n")
inline int read(){
    int a=0,b=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')b=-1;c=getchar();}
    while(isdigit(c)){a=a*10+c-'0';c=getchar();}
    return a*b;
}
const int N=50;
int n,m,T,a[N],b[N],al,ans;
char s[N];
signed main(){
    n=read();m=read();
    T=read();
    while(T--){
        for(R int j=1;j<=m;j++){
            a[j]=0;
        }
        for(R int i=1;i<=n;i++){
            scanf("%s",s);
            for(R int j=1;j<=m;j++){
                a[j]=a[j]*2+s[j-1]-'0';
            }
        }
        al=(1<<n)-1;ans=0;
        for(a[0]=0;a[0]<=al;a[0]++){
            for(R int i=0;i<=m;i++)b[i]=a[i];
            for(R int i=1;i<=m;i++){
                b[i]=(b[i]^(b[i-1]<<2)^(b[i-1]<<1)^b[i-1]^(b[i-1]>>1)^(b[i-1]>>2))&al;
                b[i+1]=(b[i-1]^b[i+1])&al;
            }
            if((b[m]&al)==0)ans++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

 
posted @ 2020-08-10 21:47  zjy1412  阅读(119)  评论(1编辑  收藏  举报