poj 3254 Corn Fields

/* Name:poj 3254 Corn Fields Author: UnimenSun Date: 18/05/2011 21:49 Description: 状态压缩 */ /* 解题报告:状态压缩 思路: 1、开数组mark[row][status],row代表当前行,status是一个二进制序列,表示row的前一行种植的状态 2、可以知道影响种植的因素有三个:1、题本身的限制即某块不能种;2、不能挨着;3、前一行已经种值状态的影响 简单的分下类:1、3一组,2自己一组 对于第一组:用T表示当前行状态,B表示上一行状态,P表示可能种植的状态 T B P 0 0 0 0 1 0 1 0 1 1 1 0 容易发现P = T & (~B) 第二组其实就是检验:1、是否挨着2、是否在不允许种的地种上了。同样用P表表示可能种植的状态,R表示将要试探的种植, S表示最终的结果,1表示这种试探是失败的,即不匀许种在这,可得真值表: R P S 0 1 0 0 0 0 1 1 0 1 0 1 容易发现有同样的结果S = R & (~P),这是验证2,验证1的话见代码check()函数中的循环 3、这些都分析完后,就可以很容易的写出dfs代码了 */ #include <iostream> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int modulo = 100000000; short g[15][15]; int m, n; int mark[15][4200]; bool check(int r, int cur) { int i; int nMax = static_cast<int>(log(r)/log(2)); if(r & (~cur)) return false; else { for(i=0; i<nMax; ++i) { if((r&1<<i) && (r&1<<(i+1))) return false; } return true; } } int dfs(int row, int status) { int ans=0; int i; int cursta = 0; if(mark[row][status]>=0) return mark[row][status]; else { for(i=0; i<n; ++i) { cursta += g[row][i] * (1<<i); } cursta &= (~status); if(row == m-1) { for(i=0; i<(1<<n); ++i) { if(check(i, cursta)) ans++; ans %= modulo; } return mark[row][status] = ans %= modulo; } else { for(i=0; i<(1<<n); ++i) { if(check(i, cursta)) ans += dfs(row+1, i); ans %= modulo; } return mark[row][status] = ans %= modulo; } } } int main() { int i, j; while(cin>>m>>n) { //输入 for(i=0; i<m; ++i) for(j=0; j<n; ++j) cin>>g[i][j]; memset(mark, -1, sizeof(mark)); int ans = 0; cout<<_cpp_max(ans, dfs(0, 0))<<endl; } return 0; }

你可能感兴趣的:(Date,IM)