题意:一个网格农场,每个格子上1表示可以放牛0表示不能放牛,相邻的格子不能放牛,问有多少种方法。
n<<12m<<12
这是经典的状压DP。第一次写,发现位运算好神奇。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define mod 100000000
using namespace std;
int dp[20][5000]; //dp[i][j]代表第i行状态为j的种数
int mp[20]; //每行的地图,用一个数表示。方便位运算操作。
bool check1(int x) { //判断这个是是不是有相邻的1
return !(x&(x>>1));
}
bool check2(int x,int y) { //判断两行是不是有相邻的1
return !(x&y);
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF) {
memset(dp,0,sizeof dp);
memset(mp,0,sizeof mp);
int x;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf("%d",&x);
mp[i]=(mp[i] << 1)|x; //生成一张地图
}
}
for(int i=0;i<(1<<m);i++) { //找到第一行合法的解
if((mp[1]|i) == mp[1]&&(check1(i))) { //前面表示是不是在地图内,后一个判断自己相不相邻
dp[1][i]=1;
}
}
for(int i=2;i<=n;i++) { //枚举行
for(int j=0;j<(1<<m);j++) { //枚举这行的状态
if((mp[i]|j)==mp[i]&&(check1(j))) { //判断是不是合法和前面相似
for(int k=0;k<(1<<m);k++) { //枚举前一行的状态
if(check2(j,k)) { //判不判断前一行是不是合法无所谓
dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;
}
}
}
}
}
int ans=0;
for(int i=0;i<(1<<m);i++) { //把最后一行累加
ans=(ans+dp[n][i])%mod;
}
printf("%d\n",ans);
}
return 0;
}