POJ 3254 Corn Fields(状态压缩dp)

来源:互联网 发布:java io流写入文件 编辑:程序博客网 时间:2024/06/05 15:31

Corn Fields
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 11850 Accepted: 6202

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


题意:有一块m*n的农场,每一格1表示能放牧,0表示不能放牧,且在放牧时,任意两头牛不能再相邻的格子里。问最多有多少种放牧方式?(不一定要尽量多放牛,一头牛不放也是一种情况)。


题解:状态压缩DP,一行一行的考虑。我们用dp[i][j]表示在第i行,到达第j种状态时的方案数。所以有状态转移方程为: dp[i][j]=sigma(dp[i-1][k]) k为所有满足条件的状态。注意要求两头牛不能放在相邻的位置,所以也要考虑到上下行两种状态是否冲突。 


具体代码和解释如下:


#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define mod 100000000 int dp[15][1<<12];int state[1<<12];//存储每一行在不出现不能放牧的位置(地图上为0)的情况下,能符合条件的状态 int rec[1<<12];//记录每一行的初始状态 int n,m,top;bool OK(int x)//判断当前状态有没有存在相邻的1,在记录的状态的情况下1表示放牧,0表示该位置不放牧 {if(x&(x<<1))return false;return true;}bool fit(int x,int y)//判断两个状态有没有在相同的位置都出现了1 {if(x&y)return false;return true;}void init(){int total=1<<n;top=0;for(int i=0;i<total;++i)//枚举所有的状态 if(OK(i))//没有相邻的两个1的状态,在这里1表示可以放的位置 state[++top]=i;//top记录在所有位置都能放牧的情况下(没有0),存在的合理放牧状态 }int main(){int i,j,k,a;while(scanf("%d%d",&m,&n)!=EOF){init();for(i=1;i<=m;++i){rec[i]=0;for(j=1;j<=n;++j){scanf("%d",&a);if(a==0)//该位置不能放牧,所以在状态中标为该位置已经安排了牛,为1 rec[i]+=(1<<(j-1));//记录下每一行的初始状态,这里的1表示这个位置是不能放牧 }}for(i=1;i<=top;++i)//初始化第一行的所有状态 {if(fit(state[i],rec[1]))//满足要求的状态 dp[1][i]=1;}for(i=2;i<=m;++i){for(j=1;j<=top;++j){if(!fit(state[j],rec[i]))//判断当前行冲不冲突 continue;for(k=1;k<=top;++k){if(!fit(state[k],rec[i-1]))//判断上一行冲不冲突 continue;if(!fit(state[k],state[j]))//判断上一行和当前行的两种状态冲不冲突 continue;dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;}}}int ans=0;for(i=1;i<=top;++i)//统计所有的情况 ans=(ans+dp[m][i])%mod;printf("%d\n",ans); }return 0;}



0 0
原创粉丝点击