POJ 2411 状态压缩DP

第一次做状态压缩DP,是因为按照DP清单里面碰到了状态不确定的DP,我当时只能用回溯做,但是时间卡得想死啊,后来又连续碰到几个题目都需要用状态压缩,所以好好学了一下,说到这里,必须要检讨一下昨天的自己,其实这道题目本应该昨天完成的,自己磨磨蹭蹭昨天非常地心不在焉,弄得昨天完全没完成训练任务。加上这个位运算这里确实有点难懂,我之前很少接触位运算,但是用状态压缩的时候位运算贯穿整个代码,所以理解起来比较难

还好找到了一个讲解非常详细的博文,这才理解了 http://www.2cto.com/kf/201208/146894.html 这个博文写的非常好

还有这个题目跑了900+MS,在学校的VJ上有100+MS过的,我看了下,先用的一个dfs在预处理,我没怎么看懂为什么是么是这样搞。。。。再说吧

注意两点:1。结果可能非常大,因此要用long long

2.行如果小于列的话,交换一下,能大大缩小时间复杂度,因为m的递增导致循环里面是成指数的增长

继续加油

#include <iostream>
#include <cstdio>
#include <cstring>
#define N (1<<11)+20
#define ll long long
using namespace std;
ll dp[12][N];
int n,m;
bool testfirst(int d)
{
    int i=0;
    while (i<m)
    {
        if (d & (1<<i))
        {
            if (i==m-1 || (d & (1<<(i+1)))==0)
            {
                return false;
            }
            i+=2;
        }
        else
            i++;
    }
    return true;
}
bool test(int a,int b)
{
    int i=0;
    while (i<m)
    {
        if ((a & (1<<i))==0)
        {
            if ((b & (1<<i))==0)
                return false;
            i++;
        }
        else
        {
            if ((b & (1<<i))==0)
                i++;
            else
            {
                if (i==m-1 || !(a& (1<<(i+1))) || !(b & (1<<(i+1))))
                {
                    return false;
                }
                i+=2;
            }
        }
    }
    return true;
}
int main()
{
    int i,j,k;
    while (scanf("%d%d",&n,&m))
    {
        if (n+m==0) break;
        if (n*m%2!=0)
        {
            puts("0");
            continue;
        }
        if (n<m)
        {
            int temp=n;
            n=m;
            m=temp;
        }
        memset(dp,0,sizeof dp);
        for (i=0; i<N; i++)
        {
            if (testfirst(i))
            {
                dp[0][i]=1;
            }
        }
        for (i=1; i<n; i++)
        {
            for (j=0; j<(1<<m); j++)
            {
                for (k=0; k<(1<<m); k++)
                {
                    if (test(j,k))
                    {
                        dp[i][j]+=dp[i-1][k];
                    }
                }
            }
        }
        printf("%lld\n",dp[n-1][(1<<m)-1]);
    }
    return 0;
}

  

posted @ 2014-01-11 11:41  KRisen  阅读(259)  评论(0编辑  收藏  举报