POJ 3254 Corn Fields

题意:Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. some of the squares are infertile and can't be planted. (1 for fertile, 0 for infertile)cows dislike eating close to each other。Please help Farmer John determine the number of ways he can choose the squares to plant.

第一道状态压缩DP题,写的还挺顺利的。

第一具备位运算常识:

  “&”  按位与: 3: 0011, 5:0101; 那么3&5: 0011

                                                                         &    0101

                                                                                0001

                             那么意味着只要有一位上都是1,那么&的结果就是>0 d的。

 “|” 按位或   只要俩个数字有一位是1 ,那么|的结果中相应位为1  3|5=0111;

“<<"  :

    x<<y 意思是x左移多少多少位 : 1<<4    是00001<<4  等于 01000  

                                                             3<<5   是 00011 <<3  等于 11000

第二:

      状态压缩DP,在我的理解中就是应用二进制数去标记所有状态。在根据二进制数本身特点去识别是不是有效状态。

  根据代码解释:dp[i][j]表示第i 行状态j 的方案数  

     dp[i][j]=dp[i][j]+dp[i-1][j]  (j为所有合法状态)

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MOD=100000000;
int dp[13][1<<12]={0,0,0};
int n,m;
int OK[1<<13];
int map[1<<13];
int main()
{
    // freopen("in.txt","r",stdin);
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&n,&m);
        int cnt=0;
        memset(OK,0,sizeof(OK));
        for(int i=0; i< (1<<m);i++)   // 枚举所有合法状态: i是一个没有连续位为1的数,如i=5:0101
        if(!(i&(i<<1))) OK[cnt++]=i; //cnt为所有合法状态的总数

        int t;
        memset(map,0,sizeof(map));
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
          scanf("%d",&t);     
          if(t==0) map[i]=map[i]|(1<<j); //用map去记录每行不可以使用的土地的状态。                                
        }                                 //例如某一行 1 0 0 0 那么这行map[x]就为0111;

        for(int i=0;i<cnt;i++) 
            if(!(map[0]&OK[i])) dp[0][i]=1; 
                                     //处理第一行 
        for(int r=1;r<n;r++) for(int i=0;i<cnt;i++)
        { 
            if(map[r]&OK[i]) continue; 
             for(int j=0;j<cnt;j++) 
              { 
                  if(map[r-1]&OK[j]||OK[i]&OK[j]) continue; 
                  dp[r][i]=(dp[r][i]+dp[r-1][j])%MOD;
             }
             
        }
        int ans=0;
        for(int i=0;i<cnt;i++) 
        ans=(ans+dp[n-1][i])%MOD; 
        printf("%d\n",ans); 
        return 0;
}   


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值