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

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.

题意:有一块n×m的土地,1表示土地可以放牛,0表示不可以放牛,牛是有脾气的,如果一块土地已经放牛了,那么,这块土地的上下左右都不能放牛。求放牛的方案数(不放牛也是一种方案)对最后答案取mod(100,000,000.)

 

思路:我们可以用状压dp来解决这个问题,首先,对于同一行来说,我们需要满足的条件有两个,①左右不能有牛,②牛只放在可以放牛的土地上。我们用一个十进制的数字来代表一行的土地的情况,假如第一行的土地情况为  0 1 1,那么,我们就用3来代表他,如过要满足条件①的话,那么就有  (3&3<<1)=0.(简单证明一下:将3左移一位,然后与3与,相当于将3的所有位和他自己的相邻位置取&,如果相邻位置为0的话,那么整个的结果就是0,否则,只要有一位不为0,结果就不为0,就说明牛的相邻位也放了牛。)如果要满足条件②的话,那么假设tmp是0 1 1每一位都取反的结果,也就是4 (1 0 0)那么有 (3&tmp)=0(简单证明一下:如果在不能放牛的土地上放牛了,假设0 1 1,我们在0的位置放牛了 这个0就变成了1 ,与tmp相对应的位置是1,他们取&的话,就不等于0,那么就是非法的,如果我们在1的位置放牛,与tmp相对应的位置都是0,取&还是0,符合条件)了解了这些后,我们就可以从0枚举到1<<m  (如果有m位的话,他的十进制表示最大为(1<<m)-1)然后统计所有合法的状态。考虑上下两行时,只要上下两行的状态 &一下为0就可以了,解释同上。也就是说,我们只需要枚举出第一行所有的状态,然后从第二行开始,依次枚举第i和i-1行就可以了

#include "iostream"
#include "vector"
#include "cstring"
using namespace std;
vector<int> state[15];
int dp[15][5000],n,m;
void get_state(int index,int x)
{
    for(int i=0;i<(1<<m);i++){
        if(i<<1&i) continue;
        if(i&x) continue;
        state[index].push_back(i);//记录状态
    }
}
int main()
{
    int tmp,x;
    while(cin>>n>>m){
        for(int i=1;i<=n;i++){
            tmp=0,state[i].clear();
            for(int j=0;j<m;j++){
                cin>>x;
                x=1-x;//每一位都取反算出tmp
                tmp=tmp*2+x;
            }
            get_state(i,tmp);//根据tmp求出所有符合条件的状态
        }
        memset(dp,0, sizeof(dp));
        for(int i=0;i<state[1].size();i++)//枚举第一行的所有可能状态
            dp[1][i]=1;
        for(int i=2;i<=n;i++)//枚举第i行和第i-1行的状态
            for(int j=0;j<state[i].size();j++)
                for(int k=0;k<state[i-1].size();k++){
                    if(state[i][j]&state[i-1][k]) continue;
                    dp[i][j]+=dp[i-1][k];
                }
        int ans=0;
        for(int i=0;i<state[n].size();i++)//最右,统计最后一行的所有情况并取mod
            ans=(ans+dp[n][i])%100000000;
        cout<<ans<<endl;
    }
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值