POJ 3254 Corn Fields(状态压缩DP)

我的第一道状态压缩DP , 题目还是很水的,

题意是再N*M的方格上,每个方格给出0 1两种状态,1是可放物品,0是不可放,问有多少种物品不相邻放置的情况,属于经典的状态压缩模型,注意下位运算的技巧,还有就是边界处理,对第一行的处理,因为这个WA了2次。

 题解参考http://bbs.cfan.com.cn/thread-1170262-1-1.html

多用一些位运算小技巧,是减少状态压缩DP代码量的很好方法

#include <cstdio>
#include <cstring>

const int mod=100000000;

int map[14];
int dp[14][1<<13];
bool valid[1<<13];
int n,m;

inline bool cannot(int x)//左移一位后与原数相与 ,为0时可行
{
    return (x<<1)&x;
}

void init ()
{
    memset (valid , true , sizeof(valid));
    for (int i=0 ; i<(1<<13) ; ++i)
    {
        if(cannot(i))valid[i]=false;
    }
}

/*bool checkonmap (int row ,int k)
{
    for (int i=0 ; i<m ; ++i,k>>=1)
    {
        if(!map[row][i] && (k&1))return false;
    }
    return true;
}*/

void debug ()
{
    for (int i=0 ; i<n ; ++i)
    {
        for (int j=0 ; j<(1<<m) ; ++j)
            printf("%d ",dp[i][j]);
        printf("\n");
    }

}

int main ()
{
    init ();
    int t;
    while (~scanf("%d%d",&n,&m))
    {
        int ans=0;
        for (int i=0 ; i<n ; ++i)
        {
            map[i]=0;
            for (int j=0 ; j<m ; ++j)
            {
                scanf("%d",&t);
                if(!t)map[i]+=1<<j;
            }
        }

        memset (dp , 0 , sizeof(dp));

        for (int i=0 ; i<n ; ++i)
        {
            for (int j=0 ; j<(1<<m) ; ++j)
            {
                if(!valid[j])continue;
                if(!i){if(!(map[i]&j))dp[i][j]=1; continue;}
                for (int k=0 ; k<(1<<m) ; ++k)
                {
                    if(!valid[k])continue;
                    if(j&k)continue;
                    if(!(map[i]&j))dp[i][j]=(dp[i-1][k]+dp[i][j])%mod;
                }
            }
        }
        //debug();
        for (int i=0 ; i<(1<<m) ; ++i)
            ans=(dp[n-1][i]+ans)%mod;
        printf("%d\n",ans);
    }
    return 0;
}


 

你可能感兴趣的:(POJ 3254 Corn Fields(状态压缩DP))