POJ3254-Corn Fields(状压dp)

来源:互联网 发布:mac微信怎么视频 编辑:程序博客网 时间:2024/05/22 14:34

原题链接:http://poj.org/problem?id=3254

Corn Fields
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 16740 Accepted: 8845

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 31 1 10 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矩阵,每个格子有两种状态,一种可以养牛,一种不行,且每两头牛不能放在相邻的格子里,问最多有多少种养牛的方法;


思路:

假如我们知道第 i-1 行放牛的所有方法的状态,那么对于第 i 行的某种方法,1.我们要判断它自身是否有相邻的牛,2.判断它与上一行有没有相邻的牛,在满足1的条件下,若有x种i-1行的方法满足2,那么这一行的这种状态就有x种方法。

由上可以得知这道题满足由子状态最优解求得整体最优解,所以可以用dp来做,但是这道题与往常的dp不一样,dp[i][j]表示的是第i行状态为j时放法的最大数

那么如何用j来保存放法呢?答案是二进制,由低位到高位0表示未放1表示放牛

比如7转化为二进制数为1001,即放 不放 不放 放;这样就能表示i行的放牛状态

那么状态转移方程就是 dp[i][j]=sum(dp[i-1][k])


代码如下:

#include<cstdio>#include<cstdlib>#include<iostream>#include<cstring>const int N = 13;const int M = 1<<N;const int mod = 100000000;using namespace std;int Map[M];int Cow[M];int dp[N][M];bool judge1(int x)  //判断二进制有没有相邻的1{    return (x&(x<<1));}bool judge2(int i,int x){    return (Map[i]&Cow[x]);}int main(){    int n,m,x;    while((scanf("%d%d",&n,&m))!=EOF)    {        memset(Map,0,sizeof(Map));        memset(Cow,0,sizeof(Cow));        memset(dp,0,sizeof(dp));        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&x);                if(x==0)                {                    Map[i]+=(1<<(j-1));                }            }        }        int k=0;        for(int i=0;i<(1<<m);i++)        {            if(!judge1(i))            {                Cow[k]=i;                k++;            }        }        for(int i=0;i<k;i++)        {            if(!judge2(1,i))            dp[1][i]=1;        }        for(int i=2;i<=n;i++)        {            for(int j=0;j<k;j++)            {                if(judge2(i,j)) continue;                for(int f=0;f<k;f++)                {                    if(judge2(i-1,f)) continue;  //去掉上一行与状态f不满足的情况                    if(!(Cow[f]&Cow[j])) //上一行的牛与这一行没有相邻                    {                        dp[i][j]+=dp[i-1][f];                    }                }            }        }        int ans=0;        for(int i=0;i<k;i++)        {            ans+=dp[n][i];            ans%=mod;        }        cout<<ans<<endl;    }}



原创粉丝点击