POJ 3254 Corn Fields 状压dp入门

来源:互联网 发布:excel数据分析占比 编辑:程序博客网 时间:2024/05/18 20:49

Corn Fields
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 15374 Accepted: 8090
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.

题意:有一片玉米地,1是肥沃,0是贫瘠,牛只能在肥沃的草地上,而且所有牛不能相邻,问有多少种方法。

大概是状压dp入门吧,之前一直对状压dp有误解2333虽然还是觉得它很难。主要是对位运算得熟悉。

每一行的状态很多,可以考虑压缩状态。[几乎每个状压dp的博主都这样写]


主要是在状态表示过后的处理
可以用位运算来处理。

bool judge1(int x){    return x&(x<<1);}

x<<1表示把x这个数二进制左移1位,十进制即*2
& 按位与 只有当两个数对应的二进制数的同一位都为1时,这一位才为1.
如果把x移一位后跟原来的数按位与后返回值时true,那么说明原数x必有两位都是相邻的1,为不合法状态。
判断上下是否相邻就两行直接与就行了。

存储土地贫瘠的方式比较巧妙

    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){           int x;           scanf("%d",&x);           if(x==0) mp[i]+=1<<(j-1);           //要想某个状态第j位为1,就1<<(j-1)           //自己想二进制的表示方法吧。        }    }//存储土地的合法状态 

这样在判断每一行是否符合土地贫瘠这一限制时,还是可以采用按位与,如果返回1,则表示原土地上是贫瘠但这个土地放了牛,也很好判断。

完整代码:

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int N = 15;const int M = 1<<N;const int mod = 100000000;int n,m;int mp[N],st[M];int dp[N][M];//dp[i][j]表示在第i行状态为j时可以放牛的数量 bool judge1(int x){    return x&(x<<1);}bool judge2(int i,int x){    return mp[i]&st[x];}bool judge3(int i,int j){    return st[i]&st[j];}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){           int x;           scanf("%d",&x);           if(x==0) mp[i]+=1<<(j-1);           //要想某个状态第j位为1,就1<<(j-1)           //自己想二进制的表示方法吧。        }    }//存储土地的合法状态     int cnt=0;    for(int i=0;i<(1<<m);i++){        if(!judge1(i))           st[++cnt]=i;    }//存储第一步合法的状态     for(int i=1;i<=cnt;i++){        if(!judge2(1,i))           dp[1][i]=1;    }    for(int i=2;i<=n;i++){        for(int j=1;j<=cnt;j++){            if(judge2(i,j)) continue;          for(int f=1;f<=cnt;f++){             if(judge2(i-1,f)) continue;             if(!judge3(j,f)) dp[i][j]+=dp[i-1][f];          }        }    }    int ans=0;    for(int i=1;i<=cnt;i++){       ans+=dp[n][i];       while(ans>=mod) ans-=mod;    }    printf("%d ",ans);    return 0;}