Corn Fields

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.


题意:

给n*m的大小的玉米地,1表示这的土地肥沃,反之表示这土地贫瘠,奶牛在肥沃的土地,且奶牛互不相邻,求分配的方案(不进行分配也是一种方案)


状态压缩+dp

每一行都有2的m次方个状态,e.g m=3 有000----111 可是这些状态有相邻的,先预处理找到所有不相邻的状态若i&(i<<1)==0,即i就是不相邻的状态,不是所有的行的不相邻的状态都是符合题意的,还与该土地的性质有关,将每一行土地的0,1转化成十进制保存起来它的状态,用数组记录十进制的反,row[i]=(row[i]<<1)|!t,接下来便开始用dp来求解,dp[i][j] i表示第i层,j表示第i层的第j的状态,状态压缩公式:dp[i][j]=dp[i][j]+dp[i-1][k];首先先把第一层的各个符合题意的状态dp[0][j]设置为1,接下来是二层,找出第i-1层符合的题意的状态与第i层符合题意的状态比较,看是否冲突,若不冲突,则dp[i][j]=dp[i][j]+dp[i-1][k],以此类推,求出最后一层,然后将最后一层的方案数求和

代码如下:

#include<iostream>
#include<stdio.h>
using namespace std;
const int N=13;
const int M=378;
const int mod=100000000;
int rec[M],row[N],dp[N][M];
int main()
{
    int n,m;
    int x=1<<12,k=0,t;
    for(int i=0;i<x;i++)
        if(!(i&(i<<1)))
            rec[k++]=i;//预处理,筛选出不相邻的状态
    rec[k]=x;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            scanf("%d",&t);
            row[i]=(row[i]<<1)|!t;
        }
    x=1<<m;
    for(int i=0;rec[i]<x;i++)//第一行所有不相邻状态
        if(!(rec[i]&row[0]))//若第一行的状态与不相邻的状态不冲突
            dp[0][i]=1;
    for(int i=1;i<n;i++)
        for(int j=0;rec[j]<x;j++)
            if(!(rec[j]&row[i-1]))//第i-1的状态与第j个不相邻的状态不冲突
            for(int k=0;rec[k]<x;k++)
                if(!(rec[k]&row[i])&&!(rec[j]&rec[k]))//第i的状态与第k个不相邻的状态不冲突且上下状态不冲突
                    dp[i][k]=(dp[i][k]%mod+dp[i-1][j]%mod)%mod;
    int ans=0;
    for(int i=0;rec[i]<x;i++)
        ans=(ans+dp[n-1][i])%mod;
    printf("%d\n",ans);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值