题目描述

德玛西亚是一个实力雄厚、奉公守法的国家,有着功勋卓著的光荣军史。

这里非常重视正义、荣耀、职责的意识形态,这里的人民为此感到强烈自豪。

有一天他们想去制裁邪恶的比尔吉沃特,于是派遣了自己最优秀的战士。

结果比尔吉沃特领土太小,只有长为n宽为m共计n*m块土地,其中有些土

地标记为0表示为高山峻岭或者深海湖泊,英雄们无法在其中站立,只有标

记为1的土地才能容纳一个英雄。德玛西亚的英雄们战斗时有一个特点,他

们不希望队友站在自己旁边显得很暧昧。请问最多能有多少种安排德玛西

亚英雄的方法?

输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 12, m <= 12 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的比尔吉沃特领土。
输出一个整数n代表安排应用的方法。(答案取膜100000000)

题解
二进制枚举、状压dp
题目给出的n,m≤12可以允许二进制的枚举范围。考虑状压dp[i][j]代表第i行安放情况为j的方法数。j用二进制表示方案。对于j要求有两点,不能有相邻的1,不能在地图上为0,即

if((j&(1<<k)&&!s[i][m-k])||(k<m-1&&j&(1<<k)&&j&(1<<k+1))){f=0;break;}

满足这两个条件,那么dp[i][j1]等于dp[i+1][j2]中合理状态和,对i+1行要求合理条件为

j1&j2!=0

转移方程为

 if(!(k&j))dp[i][j]+=dp[i+1][k]%mod,dp[i][j]%=mod;

答案就是

for(int i=0;i<(1<<m);i++){
        ans+=dp[1][i]%mod,ans%=mod;
    }

附代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define lowbit(x) x&(-x)

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll, ll> pll;

const int N = 5e5+5;
const ll mod = 100000000;
const int INF = 0x3f3f3f3f;
const double eps =1e-9;
const double PI=acos(-1.0);
const int dir[4][2]={-1,0,1,0,0,-1,0,1};
const int exdir[4][2]={1,1,1,-1,-1,1,-1,-1};

ll qpow(ll x,ll y){
    ll ans=1,t=x;
    while(y>0){
        if(y&1)ans*=t,ans%=mod;
        t*=t,t%=mod;
        y>>=1;
    }
    return ans%mod;
}

ll dp[13][(1<<12)+5];
int s[13][13],n,m;
void solve(){
    memset(dp,0,sizeof(dp));
    memset(s,0,sizeof(s));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)cin>>s[i][j];
    for(int i=n;i>0;i--){
        for(int j=0;j<(1<<m);j++){
            int f=1;
            for(int k=0;k<m;k++){
                if((j&(1<<k)&&!s[i][m-k])||(k<m-1&&j&(1<<k)&&j&(1<<k+1))){f=0;break;}
            }
            if(f){
                if(i==n)dp[i][j]=1;
                else {
                    for(int k=0;k<(1<<m);k++){
                        if(!(k&j))dp[i][j]+=dp[i+1][k]%mod,dp[i][j]%=mod;
                    }
                }
            }
        }
    }
    ll ans=0;
    for(int i=0;i<(1<<m);i++){
        ans+=dp[1][i]%mod,ans%=mod;
    }
    cout<<ans;
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    //int t;cin>>t;
    //while(t--)solve(),cout<<'\n';
    //solve();
    while(cin>>n>>m)solve(),cout<<'\n';
    return 0;
}