[USACO06NOV] Corn Fields G
题目
Description
农场主 John 新买了一块长方形的新牧场,这块牧场被划分成 M 行 N列 (1≤M≤12,1≤N≤12),每一格都是一块正方形的土地。 John 打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是 John 不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John 想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
Input
第一行:两个整数 M 和 N,用空格隔开。
第 22 到第 M+1 行:每行包含 N 个用空格隔开的整数,描述了每块土地的状态。第 i+1 行描述了第 i 行的土地,所有整数均为 0 或 1 ,是 1 的话,表示这块土地足够肥沃,0 则表示这块土地不适合种草。
Output
一个整数,即牧场分配总方案数除以 100,000,000的余数。
Sample Input
2 3 1 1 1 0 1 0
Sample Output
9
思路
一道状压$dp$题;
用$dp[i][k]$表示第$i$行的种植状态$k$;
把不符合种植条件的状态去掉;
再枚举上一行的状态;
若两行状态没有相邻种植,$dp[i][k]$ 加上上一行方案再取模即可;
代码
#include<bits/stdc++.h> typedef long long ll; using namespace std; const ll _=13; ll n,m; ll a[13][13],dp[13][1<<12]; int main() { scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) scanf("%lld",&a[i][j]); dp[0][0]=1; for(ll i=1;i<=n;i++) for(ll k=0;k<=(1<<m)-1;k++) { if(k&(k>>1)) continue;//不能左右相邻种植 ll flag=0; for(ll j=1;j<=m;j++) if(a[i][j]==0&&k&(1<<(j-1)))//只能在肥沃的土地上种植 { flag=1; break; } if(flag) continue; for(ll l=0;l<=(1<<m)-1;l++) if(!(k&l))//与上一行状态没有相邻种植 dp[i][k]=(dp[i][k]+dp[i-1][l])%100000000;//加上方案 } ll ans=0; for(ll i=0;i<=(1<<m)-1;i++) ans=(ans+dp[n][i])%100000000; printf("%lld",ans); return 0; }