链接:https://vjudge.net/problem/POJ-3254#author=freeloop
题意:
农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
思路:
状压dp,二进制表示每一行的状态,储存时使用十进制。
具体思路注释。
代码:
#include <iostream> #include <memory.h> #include <string> #include <istream> #include <sstream> #include <vector> #include <stack> #include <algorithm> #include <map> #include <queue> #include <math.h> #include <cstdio> using namespace std; typedef long long LL; const int MAXN = 15; const int STATES = 600; const int MOD = 1e9; //377 最多状态 int cur[MAXN]; int dp[MAXN][STATES]; int states[STATES]; int pos = 0; void Init(int w) { int total = (1 << w); for (int i = 0;i < total;i++) { if(!(i&(i<<1)))//i往左位移以为,是否有两个1重叠,重叠不满足 states[++pos] = i; } } int main() { int n, m; int flag; scanf("%d%d", &m, &n); Init(n); for (int i = 1;i <= m;i++) for (int j = 1;j <= n;j++) { scanf("%d", &flag); if (!flag)//方便判断某种状态是否满足,0时加 cur[i] += (1 << (n - j)); } for (int i = 1;i <= pos;i++) { if ((cur[1] & states[i]) == 0)//状态为1表示种,同时行状态为1表示不能种 dp[1][i] = 1; } for (int i = 2;i <= m;i++) { for (int j = 1;j <= pos;j++) { if (states[j] & cur[i])//枚举的状态是否冲突当前行 continue; for (int k = 1;k <= pos;k++) { if (states[k] & cur[i - 1])//枚举的上一行状态是否冲突 continue; if (states[j] & states[k])//枚举的上下两行状态是否冲突 continue; dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD; } } } int res = 0; for (int i = 1;i <= pos;i++) res = (res + dp[m][i]) % MOD; printf("%d ", res); return 0; }