[USACO06NOV]玉米田Corn Fields 解题报告(状压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:  
2 3
1 1 1
0 1 0
输出样例#1:  
9






解题报告

    m和n都很小,很容易就看出来是状压DP。那么我们每一行的状态就可以用一个二进制数来表示,1代表种了草,0代表每种,由于不允许有种草的相邻,那么我们可以预先把合法的情况先存下来(不存应该也没事),这样可以省时。还有一件重要的事,就是存地图的时候把1按0存,把0按1存,后面就知道有什么用了。

    假设合法状态就存在ZT[i]里,ZT[i]表示合法的第i种状态(以下简称状态i)。我们用Opt[i][j]表示第i行为状态j时的方案数。

    转移方程就是:Opt[i][j]=ΣOpt[i][k];

    要满足的条件为:状态j在第i行合法(即ZT[j]&Map[i]==0),状态k在第i-1行合法(即ZT[k]&Map[i-1]==0),以及状态j和状态k不冲突(即ZT[j]&ZT[k]==0),因为上下也不能相邻。

    初始化的时候只能把Opt[0][1]赋值为1,即第0行什么也不放的方案数为1。

源代码

#include
#define Mod 100000000
using namespace std;
int m,n,i,j,Ans,Opt[21][5001],Map[21],ZT[5001],x,Cnt,k;
int main(){
	scanf("%d%d",&m,&n);
	for(i=1;i<=m;++i){
		for(j=0;j

你可能感兴趣的:(动态规划,二进制)