状态DP中很经典的一道题,除了从牛变成人之后好像就没什么变化了吧。
可以预处理出同一行内不会相邻的所有状态。
地图的每一行的01互换后,用一个数字储存。
对于每一个状态,若其与地图&运算的结果不为0,则说明有英雄站在不合法的地方了。
状态的转移则是枚举相邻两行间的状态,若相与为0,则可转移。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2<<13;
const int maxm=150005;
const int mod=100000000;
int n,m,siz;
int hang[13];
ll dp[13][maxn];
vector<int> leg;
bool legal(int num){
for(int i=0;i<m-1;i++){
if(((1<<i)&num)&&((1<<(i+1))&num))return 0;
}
return 1;
}
int cc;
int main(){
while(~scanf("%d%d",&n,&m)){
leg.clear();
memset(dp,0,sizeof(dp));
int upper=(1<<m) -1;
for(int i=0;i<upper;i++){
if(legal(i))leg.push_back(i);
}
siz=leg.size();
for(int i=0;i<n;i++){
hang[i]=0;
for(int j=0;j<m;j++){
scanf("%d",&cc);
if(cc==0){
hang[i]+=(1<<j);
}
}
}
for(int i=0;i<siz;i++){
int u=leg[i];
if(hang[0]&u)continue;
else dp[0][u]=1;
}
for(int i=0;i<n-1;i++){
for(int j=0;j<siz;j++){
int u=leg[j];
if(dp[i][u]==0)continue;
for(int k=0;k<siz;k++){
int v=leg[k];
if(u&v)continue;
if(hang[i+1]&v)continue;
dp[i+1][v]=(dp[i+1][v]+dp[i][u])%mod;
}
}
}
ll ans=0;
for(int i=0;i<siz;i++){
int u=leg[i];
ans=(ans+dp[n-1][u])%mod;
}
printf("%d\n",ans);
}
return 0;
}