Corn Fields POJ - 3254 (状压dp)
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
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
Sample Input
2 3 1 1 1 0 1 0
Sample Output
9
Hint
1 2 3
4
There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.
题意:题目大意:农夫有一块地,被划分为m行n列大小相等的格子,其中一些格子是可以放牧的(用1标记),农夫可以在这些格子里放牛,其他格子则不能放牛(用0标记),并且要求不可以使相邻格子都有牛。现在输入数据给出这块地的大小及可否放牧的情况,求该农夫有多少种放牧方案可以选择(注意:任何格子都不放也是一种选择)
思路:看见牛与牛之间不能相邻,这样就要求每一行中不能存在两个相邻的1,然后就是根据上一行的状态转移到当前行的状态的问题,能想到状压dp:。
思路来源:https://blog.csdn.net/harrypoirot/article/details/23163485
代码:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for (int a = b; a <= c; a++)
#define RFOR(a, b, c) for (int a = b; a >= c; a--)
#define off ios::sync_with_stdio(0)
#define sc(a) scanf("%d",&a)
#define pr(a) printf("%d\n",a);
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;//1e10
const int mod = 1e8;
const int Maxn = 1e9+7;
const double pi = acos(-1.0);
const double eps = 1e-8;
int n, m, top; //top表示每行最多的状态数
int state[Maxn];//所有可能方案
int dp[20][Maxn];//对于前i行数据,每行有前j种可能时候的解
int cur[20];//表示第i行整行的时候
inline bool ok(int x) { //判断x的二进制数是否有相邻的1
if (x & x << 1) return false; //x有相邻的1,不合法
return true; //合法
}
void init() { //初始化合法的方案
top = 0;
int total = 1 << n; //遍历状态的上界
for (int i = 0; i < total; i++) {
if (ok(i)) state[++top] = i;
}
}
inline bool fit(int x, int k) { //判断x与第k行的实际状态的逆是否有 重合'
if (x & cur[k]) return false;//若有重合,则x不符合要求
return true;
}
int main() {
scanf("%d%d", &m, &n); //m行n列
init();
mem(dp, 0);
FOR(i, 1, m) {
cur[i] = 0;
int num;
FOR(j, 1, n) {
sc(num);
if (num == 0)//若该格为0
cur[i] += (1 << (n - j));//则将该位置为1(注意要以相反方式存储,即1表示不可放牧
}
}
FOR(i, 1, top) {
if (fit(state[i], 1)) { //判断所有可能状态与第一行的实际状态的逆是否有重合
dp[1][i] = 1; //若第1行的状态与第i种可行状态吻合,则dp[i][j]标为1
}
}
/*
状态转移过程中,dp[i][k] =Sigma dp[i-1][j] (j为符合条件的所有状态) */
for (int i = 2; i <= m; i++) { // i索引第2行到第m行
for (int k = 1; k <= top; k++) { //找出一组与第i行相符的state[k]
if (!fit(state[k], i))continue;
for (int j = 1; j <= top; j++) { // //找到state[k]后,再找一组与第i-1行符合,且与第i行(state[])不冲突的状态state[j]
if (!fit(state[j], i - 1))continue; //判断是否符合第i-1行情况
if (state[k] & state[j]) continue; //判断是否与第i行冲突
dp[i][k] = (dp[i][k] + dp[i - 1][j]) % mod; //皆可通过将'j'累加到'k'上
}
}
}
int ans = 0;
FOR(i, 1, top) {
ans = (ans + dp[m][i]) % mod; //累加最后一行所有可能状态的值
}
pr(ans);
}

浙公网安备 33010602011771号