POJ 3254 Corn Fields 状压DP

题意:给出N*M的01矩阵(N<12&&M<12),0不可以种草,1可以种草,要求种的草不能相邻(不可以共享一个边),问有多少种种法

第一道状压DP,应该来说不算难,看了这个博客,受益很大  http://www.cnblogs.com/ka200812/archive/2011/08/11/2135607.html

注:DFS的话,2的次方级,会爆的。 由题目的特点,下一行只受上一行的影响,而且还有重复计算(下一行的某一状态的数量由上一行得来),说的那么乱呢,

看连接的博客吧,讲的真不错

1.判断一个二进制数有没有相邻的两位同为1的方法 i&(1<<1)||i&(i>>1) 位运算的优先级比较低,一般加()

2.判断两个二进制的数有没有相同位上都为1  直接相与 。 为了方便,代码中还把输入翻了过来,1变成0,0变成1,为了Get_state()里面找状态方便...

代码(带预处理的 0MS):

/*
vector
vetor<int>num[];
num[i].clear();
num[i].push_back();
num[i].size();
num[i][j]
*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#define MOD 100000000
#define ll __int64
using namespace std;
int state[13][8192];
ll dp[13][8192];
vector<int>num[13];
int r,c;
void Get_state(int row,int temp)
{
    num[row].clear();
    for(int i=0;i<(1<<c);i++)
    {
        if(i&(i>>1)||i&(i<<1)) continue;
        if(i&temp) continue;
        num[row].push_back(i);
    }
}
int main()
{
    int i,j,k;
    int temp;
    while(~scanf("%d%d",&r,&c))
    {
        for(i=0;i<r;i++)
        {
            temp=0;
            for(j=0;j<c;j++)
            {
                scanf("%d",&k);
                k=1-k;
                temp=(temp<<1)+k;
            }
            Get_state(i,temp);
        }
        memset(dp,0,sizeof(dp));
        for(i=0;i<num[0].size();i++) dp[0][i]=1;
        for(i=1;i<r;i++)
        {
            for(j=0;j<num[i].size();j++)
            {
                for(k=0;k<num[i-1].size();k++)
                {
                    if(num[i][j]&num[i-1][k]) continue;
                    dp[i][j]+=dp[i-1][k];
                }
            }
        }
        int ans=0;
        for(i=0;i<num[r-1].size();i++)
        {
            ans=(ans+(dp[r-1][i]%MOD))%MOD;
        }
        printf("%d\n",ans);
    }
    return 0;
}

没有预处理的,dfs枚举每一行

代码(16MS):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define nMAX 13
#define ll __int64
#define MAX (1<<12)
#define MOD 100000000
using namespace std;
ll dp[nMAX][MAX+2];
int map[nMAX][nMAX];
int r,c,i,j;
void dfs(int col,int state)
{
    if(col==c) {dp[i+1][state]+=dp[i][j]; return ;}
    if(map[i+1][col]==0) {dfs(col+1,state); return ;}//不可以放
    if(j&(1<<col))  //上一行放了,不可以放
    {
        dfs(col+1,state);
    }
    else
    {
        if(col==0) dfs(col+1,state+(1<<col));
        else if((state&(1<<(col-1)))==0) dfs(col+1,state+(1<<col));//以后涉及位运算的都加()就是了
        dfs(col+1,state);
    }
}
int main()
{
    int k;
    while(~scanf("%d%d",&r,&c))
    {
        for(i=1;i<=r;i++) //空出一行
            for(j=0;j<c;j++)
                scanf("%d",&map[i][j]);
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(i=0;i<r;i++)
        {
            for(j=0;j<(1<<c);j++)
            {
                if(dp[i][j]) dfs(0,0);//0 0表示i+1行左边起第0个,状态为0
            }
        }
        int ans=0;
        for(i=0;i<(1<<c);i++)
        {
            ans=(ans+dp[r][i])%MOD;
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

posted @ 2012-10-05 20:59  快乐.  阅读(138)  评论(0编辑  收藏  举报