poj 3254 Corn Fields

题目:

Description

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.

Sample Input

2 3
1 1 1
0 1 0

Sample Output

9

Hint

Number the squares as follows:
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标记),并且要求不可以使相邻格子都有牛。现在输入数据给出这块地的大小及可否放牧的情况,求该农夫有多少种放牧方案可以选择(注意:任何格子都不放也是一种选择,不要忘记考虑! )

状态压缩dp。
用二进制数据表示每个放格放不放牛,并且放牛格子不相邻,然后转化成十进制记录不同的状态。state[1<
dp[i][j]表示第i行状态为j时的放牧方案个数。
对于状态j要判断是否可以存在。
当第i行有状态j存在,再找第i-1行是否有状态k存在,如果存在,再判断第i行的状态j和第i-1行的状态k是否存在放牛格子相邻,相邻就舍弃。
最后把第n-1行所有的状态的方案加起来即为所求。

代码:

#include
#include
#include
#include
using namespace std;
int state[1<<12];//所有的可能放法状态
int map[13];//map[i]表示每行土地的当前状态取反之后的结果
int dp[13][1<<12];//dp[i][j]表示第i行状态为j时放法
int tol,n,m;
const int mod = 100000000;
void findAllState(){
    tol = 0;
    for (int i = 0; i < (1 << n); i++){
        if ((i&(i << 1))==0){ //如果状态i满足相邻两位数不同时为1,表示此状态可行
            state[tol++] = i;
        }
    }
}//找出所有的可能放法状态
bool judge(int st,int m){
    return state[st] & map[m]; //如果返回false则满足
}//判断可能状态state是否满足土地当前状态
int main()
{
    while (scanf("%d%d", &m, &n)!=EOF){
        memset(dp,0,sizeof(dp));
        memset(map,0,sizeof(map));
        memset(state,0,sizeof(state));
        int x;
        for (int i = 0; i < m; i++){
            for (int j = 0; j < n; j++){
                scanf("%d",&x);
                if (x == 0){
                    map[i] +=(1<//对土地状态进行取反
        findAllState();
        for (int i = 0; i < tol; i++){
            if (!judge(i, 0)){
                dp[0][i] = 1;
            }
        }//对第0行初始化
        for (int i = 1; i < m; i++){
            for (int j = 0; j < tol; j++){
                if (judge(j, i)){
                    continue;//状态j不满足第i行土地状态
                }
                for (int k = 0; k < tol; k++){
                    if (judge(k, i - 1)){
                        continue;//状态j不满足第i-1行土地状态
                    }
                    if (!(state[j] & state[k])){
                        dp[i][j] += dp[i - 1][k];
                    }//判读竖直方向上是否有相邻两位数同时为1
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < tol; i++){
            ans += dp[m - 1][i];
            ans %= mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(动态规划)