Problem
Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can’t be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.
Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.
Input
Line 1: Two space-separated integers: M and N
Lines 2… M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)
Output
Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.
题意:有个M×N的方格图,牛食草,方格值为1即可食草,0不可,放牧的位置不可连续,求一共多少种方案(不食草也是一种方案)
典型的状压dp题,每行的情况降维压缩,开一个二维dp数组存储方案数,最后累加取模,具体详见代码注释
AC代码
#include<iostream>
#include<string>
using namespace std;
int M, N;
const int mod = 100000000;
int vis[30];//cur[i]表示第i行整行的情况,用二进制数表示
int state[700];//state数组存每行满足不连续食草的所有可能状态
int dp[30][700];//dp数组表示第i行的第j种状态有多少种方案
int num, top = 0;
inline bool judge(int x)//判断状态x是否可行
{
if (x & x << 1)return false;else return true;
}
void init()
{
int total = 1 << N;//total表示一行状态的总数top = 0;//top表示一行满足不连续食草的可能状态总数for (int i = 0; i < total; i++){
if (judge(i)){
state[++top] = i;}}
}
inline bool fit(int x, int k)//用来判断某行的一种状态是否与原情况相符合,比如0的地方不能突然出了个1,是不符合的
{
if (x & vis[k])return false;else return true;
}
int main()
{
cin >> M >> N;init();for (int i = 1; i <= M; i++){
for (int j = 1; j <= N; j++){
cin >> num;if (num == 0)//只能存逆状态,方便初始化第一行状态{
vis[i] += (1 << (N - j));}}}for (int i = 1; i <= top; i++){
if (fit(state[i], 1))//记住要初始化第一行dp[1][i] = 1;}for (int i = 2; i <= M; i++)//从第二行开始递推统计方案数{
for (int k = 1; k <= top; k++)//出现不符合情况的一律continue,出现符合为止{
if (!fit(state[k], i)) continue;for (int j = 1; j <= top; j++){
if (!fit(state[j], i - 1)) continue;if (state[k] & state[j])continue;dp[i][k] = (dp[i][k] + dp[i - 1][j]) % mod;//状态转移方程}}}int ans = 0;for (int i = 1; i <= top; i++){
ans = (ans + dp[M][i]) % mod;//最后一行每种状态对应方案数累加}cout << ans << endl;
}