POJ 3254 Corn Fields(状压DP)

Corn Fields

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 20465   Accepted: 10725

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.

Source

USACO 2006 November Gold

借鉴:https://www.cnblogs.com/Ronald-MOK1426/p/8451875.html

该题的状态转移: 当前状态的种类数==之前状态所有状态满足当前状态的限制条件的种类数(因为是枚举,所以同层的当前状态也是有很多种)

状态DP:DP的定义: i,j变成二进制来定义状态

本题的dp定义:第i行为j这二进制状态的种类。

(下可以承接上的,这样是不是理解了)

答案由最后一行所有状态的种类累加

状压dp 通常是三个for

#include<cstdio>
#include<iostream>
#include<cctype>
#define mod 100000000    
using namespace std;
int n,m,tot,ans,state[1500],dp[15][1500],cur[15];      //dp表示当前最大值,第一维是行数,第二维是状态数,cur是每行的情况,state是预存的可能状态
bool fit(int x,int k)                                  //判断当前状态是否符合当前行
{
    return !(state[x]&cur[k]);  //就是完全重合的话,是要用当前状态取反再与另一个数比较,0,的话则是完全重合
                                //因为1的状态太多,而0的状态是有限的所以,用0来判定是很好的。
                                //判定的方法,不能取的地方不能取
                                //可取的地方可取可不取
                                //这个第一个可取与不可取是根据实际地图而言的
}
void init()                    //初始化
{
    int sum=1<<n,i;            //列举可能状态,并预存
    for(i=0;i<sum;i++)
    if(!(i&(i<<1)))            //判断该数是否含有连续的1,如果含连续的1则不满足条件,这个功能就是除去含连续1的情况
    state[++tot]=i;            //tot存的是不相邻1的所有状态,这样就满足了题目中的条件1.
                               //state是限定条件。
}
                    
int main()
{
    int i,j,k;
    scanf("%d%d",&m,&n);
    init();
    for(i=1;i<=m;i++)
    for(j=1;j<=n;j++)
    {
        scanf("%d",&k);         
        if(!k)                //当该土地是贫瘠的土地时
        cur[i]+=(1<<(n-j));   //再次强调cur存的是每一行的状态
                              //cur是地图的实际情况
    }
    for(i=1;i<=tot;i++)       //初始化第一行
    if(fit(i,1))              //第一行不用承上,只要判断不连续 
    dp[1][i]=1;
    for(i=2;i<=m;i++)                           //枚举行
    for(j=1;j<=tot;j++)                         //枚举当前状态
    {
       if(!fit(j,i))        continue;           
       for(k=1;k<=tot;k++)                      //枚举上一层可行状态
                                                //每次枚举都要判断条件1,条件1每次都要重头开始判
       {
          if(!fit(k,i-1))   continue;           //从第二行开始,就要判断前面的一行。
          if(state[j]&state[k])    continue;    //如果当前行与上一行有相邻则跳过。
          dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;   //当前这一状态的种类数,为上一行所有满足情况的种类数再满足当前这一行的限制剩下的种类数。
       }
    }
    for(i=1;i<=tot;i++)
    ans=(ans+dp[m][i])%mod;
    printf("%d",ans);
    return 0;

猜你喜欢

转载自blog.csdn.net/xigongdali/article/details/82745737