zoukankan      html  css  js  c++  java
  • 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
    ",dp[n-1][(1<<m)-1]);
        }
        return 0;
    }
    

      

  • 相关阅读:
    10-23C#基础--结构体
    10-23C#基础--特殊集合(stack、queue、hashtable)
    10-21C#基础--集合
    10-20C#基础---一维、二维数组&&冒泡排序
    10-19C#基础--第四部分类型(2)重点
    10-17C#第四部分--类型(1)
    10-17C#语句(3)--跳转语句、异常处理语句
    10-16C#for...循环语句(2)
    C# DEBUG 调试信息打印及输出详解
    .NET中值得体验的精妙设计
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3514847.html
Copyright © 2011-2022 走看看