题面:
农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
输出一个整数,即牧场分配总方案数除以100,000,000的余数。
题解:
emmm。。。一道不难的状压DP
设f[i][j]表示到i行,状态为j的方案数,
因为相邻两块土地不能选,所以我们可以先dfs搜出所有可能状态,
这样状态数暴跌10倍,,,貌似很划得来的样子,不过不这样好像也可以,但是DP判断的地方也会麻烦一些。。。
然后存下不能放的地方,并标记为1,(同样用状压)
依次枚举行,当前状态,上一行状态,统计并取模即可
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 15
#define LL long long
#define mod 100000000
int n,m,tmp,ans,tot;
int f[AC][],s[AC],num[];//error!!!状态要开400,,, void pre()
{
int a;
scanf("%d%d",&n,&m);
for(R i=;i<=n;i++)
for(R j=;j<=m;j++)
{
scanf("%d",&a);
if(!a) s[i] |= << (m - j);//给定状态也要压
}
} void dfs(int x,int now)
{
if(x) tmp+= << (m - now);
if(now == m)
{
num[++tot]=tmp;
if(x) tmp-= << (m - now);
return ;
}
if(x) dfs(,now+);
else
{
dfs(,now+);
dfs(,now+);
}
if(x) tmp-= << (m - now);
} void work()
{
for(R i=;i<=tot;i++)//第一行特殊处理
{
if(s[] & num[i]) continue;
f[][i]=;
}
for(R i=;i<=n;i++)//枚举行
{
for(R j=;j<=tot;j++)//枚举当前行状态
{
if(s[i] & num[j]) continue;
for(R k=;k<=tot;k++)//枚举上一行状态
{
if(s[i-] & num[k]) continue;
if(num[j] & num[k]) continue;
f[i][j] += f[i-][k];
f[i][j] %= mod;
//if(f[i][j] > mod) f[i][j] -= mod;
}
}
}
for(R i=;i<=tot;i++)
{
ans+=f[n][i];
ans%=mod;
//if(ans > mod) ans-=mod;
}
printf("%d\n",ans);
} int main()
{
// freopen("in.in","r",stdin);
pre();
dfs(,);//获取所有有效状态
dfs(,);
work();
//fclose(stdin);
return ;
}