首先判断这是状压dp的题(判断方法)
题目描述
农场主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的余数。
样例 #1
样例输入 #1
2 3
1 1 1
0 1 0
样例输出 #1
9
思路
题目要求计算方案数
由状压性质得到dp数组:
F [ i , j ] : 前 i 排 已 经 安 排 过 且 第 i 排 的 种 法 为 j 的 方 案 数 F[i,j]:前 i 排已经安排过 且 第i排的种法为j的方案数 F[i,j]:前i排已经安排过且第i排的种法为j的方案数
继而得到状态转移方程(题目的限制条件即为转移方程):
我们知道每个玉米田都是十字形的因为每棵玉米上下左右都不能种了(娇贵玉米)
可以设二进制下的 j j j, 1 1 1 为种玉米, 0 0 0 为不种。
例 如 : j = 0101 , 说 明 位 置 1 , 3 不 种 玉 米 , 2 , 4 种 玉 米 。 例如:j=0101,说明位置1,3不种玉米,2,4种玉米。 例如:j=0101,说明位置1,3不种玉米,2,4种玉米。
有一些土地是荒废的,即那一行 j j j 的二进制该位为 0 0 0 。
观察发现10,01,00是可以挨在一起的,而11不行,即:
&
运算,(1&1=1,1&0=0,0&0=0)保证a&b=0即可。
CODE
#include<iostream>
using namespace std;
using ll=long long;
const int mod=1e9;
int n,m;
int fld[13][13],plc[13],g[5000];
int f[13][5000];//根据设置的转态,最多12行,每行有2^12=4096种状态
int main() {
cin>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++){
cin>>fld[i][j];
plc[i]=(plc[i]<<1)+fld[i][j];
}
for(int i=0;i<(1<<n);i++){
if(!(i&(i>>1))&&!(i&(i<<1))){
g[i]=1;
if((i&plc[1])==i)f[1][i]=1;
}
}
for(int i=2;i<=m;i++){
for(int j=0;j<(1<<n);j++){
if(((j&plc[i-1])==j)&&g[j])
for(int k=0;k<(1<<n);k++)
if(((k&plc[i])==k)&&!(j&k)&&g[k]){
f[i][k]=(f[i][k]+f[i-1][j])%mod;
}
}
}
int ans=0;
for(int i=0;i<(1<<n);i++)ans=(ans+f[m][i])%mod;
cout<<ans;
}
记得取模