poj3254 状压dp入门题

Corn Fields
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 8691 Accepted: 4634

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位二进制数范围是[00...00,11...11],0和1的个数均为m

此题有一些限制条件:

每行有肥沃区(用1表示)和非肥沃区(用0表示),那么每行都可以用一个数字表示。

有牛用1表示,没牛用0表示,则一行如何放置牛也可用一个数字,因为牛必须在肥沃区,也就是原先该行有1的地方必须覆盖该行放置牛的状态(有1的地方),这个用按位或运算就可以了,如果覆盖就等于原先的状态。

本行不能有相邻的牛,也就是不能有相邻的1,我们将数字左移一位,最左一位和最右一位都与0&,而中间部分刚好是相邻位&,若没有相邻1,那显然结果为0.

与上行在同一列不能有牛,和上面类似,直接拿上一行放置牛的状态与本行&,结果为0,就是符合条件的。

dp就按照常规来,dp[i][s]表示第i行为状态s的种数,显然dp[i][s]=sigma(dp[i-1][t]),((t&s)==0&&t,s均为合法状态)

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 4100
using namespace std;

const int mod=100000000;
int r[15],dp[15][Maxn];
int st[Maxn];
int main()
{
    int n,m,x;
    while(cin>>n>>m){
        for(int i=1;i<=n;i++){
            r[i]=0;
            for(int j=1;j<=m;j++){
                cin>>x;
                r[i]=r[i]<<1|x;
            }
        }
        int top=0;
        for(int i=0;i<1<<m;i++) //预处理本行相邻位不同为1
            if(!(i&i<<1)) st[top++]=i;
        memset(dp,0,sizeof dp);
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<top;j++){
                if((st[j]|r[i])!=r[i]) continue; //与本行冲突
                for(int k=0;k<top;k++) //i-1行非法状态dp均为0,因此直接加在dp[i][]上
                    if(!(st[j]&st[k])) //与上一行同位不同为1
                        dp[i][st[j]]=(dp[i][st[j]]+dp[i-1][st[k]])%mod;
            }
        int ans=0;
        for(int i=0;i<top;i++)
            ans=(ans+dp[n][st[i]])%mod;
        printf("%d\n",ans);
    }
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值