POJ 3254 Corn Fields (状态压缩DP)

题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)

思路:dp[i][s] 代表第i行状态为s(s是每个位置放与不放组成的0-1序列对应的十进制数)时所能得到的方案总数

递推方程:dp[i][s] = Σdp[i-1][f]  (f为i-1行的状态)

判断状态合法的方案是,s中不能有相邻的1,s中的1必须满足题目给定矩阵,即矩阵有1的地方s可以放1,s与f不能在同一位置有1。

初始化:dp[1][s] = 0或1(代表第一行状态为s是否合法)

#include<cstring>
#include<cstdio>
#define mod 1000000000
int stk[400],top,N,M,a[15][15],dp[15][400];
inline bool checkline(int i,int x)
{
    for(int j=0,pre=0;j<M;++j,pre=x&1,x/=2)
        if(x&1 && !a[i][j+1]) return 0;
    return 1;
}
inline bool checkline(int x)
{
    for(int j=0,pre=0;j<M;++j,pre=x&1,x/=2)
        if(x&1 && pre) return 0;
    return 1;
}
void init()
{
    memset(dp,0,sizeof(dp));
    top=0;
    for(int s=0;s< (1<<M) ;++s)
        if(checkline(s)) stk[top++]=s;
}
int main()
{
    while(~scanf("%d%d",&N,&M))
    {
        for(int i=1;i<=N;++i)
        for(int j=1;j<=M;++j) scanf("%d",&a[i][j]);
        init();
        for(int j=0;j<top;++j) dp[1][j]=checkline(1,stk[j]);
        for(int i=2;i<=N;++i)
        for(int j=0;j<top;++j)
        {
            if(!checkline(i,stk[j])) continue;
            for(int k=0;k<top;++k)
            {
                if((stk[j]&stk[k]) || !checkline(i-1,stk[k])) continue;
                dp[i][j] = (dp[i][j]%mod+dp[i-1][k]%mod)%mod;
            }
        }
        int ans=0;
        for(int j=0;j<top;++j)
            ans = (ans%mod+ dp[N][j]%mod)%mod;
        printf("%d\n",ans);
    }
    return 0;
}




你可能感兴趣的:(优化,动态规划,poj,状态压缩)