导航

POJ 3254 【状态压缩DP】

Posted on 2015-11-06 19:30  tun~  阅读(133)  评论(0编辑  收藏  举报

题意:

给一块n*m的田地,1代表肥沃,0代表贫瘠。

现在要求在肥沃的土地上种草,要求任何两个草都不能相邻。

问一共有多少种种草的方法。

种0棵草也是其中的一种方法。

n和m都不大于12.

思路:

状态压缩DP,dp[i][j]代表在第i行状态j一共有多少种可能的种植方法。

j是二进制转化而来的状态,0代表不种草,1代表种草。

dp[i]只受到两个限制,即dp[i-1]的某种状态,和当前土地的贫瘠状况。

只要保证&操作之后重复的为0就可以了

最后输出sum(dp[n][1...w])(w代表一共有w种可行的状态)

#include<stdio.h>
int pho[15][15];
int biao[15];
int dp[15][1<<13];
int may[1<<13];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&pho[i][j]);
            if(pho[i][j])
            {
                pho[i][j]=0;
            }
            else
            {
                pho[i][j]=1;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        int tmp=pho[i][1];
        for(int j=2;j<=m;j++)
        {
            tmp=tmp<<1;
            tmp+=pho[i][j];
        }
        biao[i]=tmp;
    }
    int num=1;
    for(int s=0;s<(1<<m);s++)
    {
        if((s&(s<<1))==0)
        {
            may[num++]=s;
        }
    }
    for(int i=1;i<num;i++)
    {
        if((may[i]&biao[1])==0)
        {
            dp[1][i]=1;
        }
    }
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<num;j++)
        {
            for(int k=1;k<num;k++)
            {
                if((may[k]&may[j])||(may[j]&biao[i]))
                    continue;
                dp[i][j]+=dp[i-1][k];
                dp[i][j]%=1000000000;
            }
        }
    }
    int ans=0;
    for(int i=1;i<num;i++)
    {
        ans+=dp[n][i];
        ans%=1000000000;
    }
    printf("%d\n",ans);
    return 0;
}