题目描述
农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
输入输出格式
输入格式:
第一行:两个整数M和N,用空格隔开。
第2到第M+1行:每行包含N个用空格隔开的整数,描述了每块土地的状态。第i+1行描述了第i行的土地,所有整数均为0或1,是1的话,表示这块土地足够肥沃,0则表示这块土地不适合种草。
输出格式:
一个整数,即牧场分配总方案数除以100,000,000的余数。
学了一年了,状压dp还是萌新
想讲的都在代码里了
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int mod=1e8;
int n,m;
int sq[14][14];
int mp[14];
bool judge[(1<<13)-1];
int dp[14][(1<<13)-1];
long long ans=0;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&sq[i][j]);
mp[i]=(mp[i]<<1)+sq[i][j];
}//第一步,把地图转化为二进制
for(int s=0;s<(1<<m);s++)
{
if( (s&(s<<1))==0 && (s&(s>>1))==0 ) judge[s]=1;
}//第二步,判断状态是否合法
for(int s=0;s<(1<<m);s++)
{
if( (judge[s]) && (s&mp[1])==s) dp[1][s]=1;
}//第三步,找出第一行状态的方案数
for(int i=2;i<=n;i++)
{
for(int s=0;s<(1<<m);s++)//当前状态
{
if( (judge[s]) && ((s&mp[i])==s))//当前状态成立
{
for(int t=0;t<(1<<m);t++)//上一行状态
{
if((s&t)==0)//当前状态与上一行状态不冲突
{
dp[i][s]=(dp[i][s]+dp[i-1][t])%mod;
}
}
}
}
}//第四步,按行dp
for(int s=0;s<(1<<m);s++)
{
ans=(ans+dp[n][s])%mod;
}//第五步,最后一行记录答案
printf("%lld\n",ans);
}