• 寒假Day54:POJ3254Corn Fields状压dp入门题


    题意:

    给出n、m,接下去给出n行m列的状态(只有0或1),

    只能在1的位置种植,并且如果这块地方种植了,那么其上下左右,也就是相邻部分不可种植,

    问:总共有多少种种草方案。

    思路:状压dp入门

    状压dp求解什么样的问题?

    数据范围比较小;简单算法无法解决。

    一般动态规划无法解决,因为一般的dp转移方程只能从一边过来,

    这一题需要上下左右都要考虑到。

    本质:利用位运算记录状态,从而实现dp

    本题的状态划分:每一行作为一个状态,

    从而达到:第i行的状态从 i - 1 行转移,并且只从它转移。

    也就是说,第 i 行的状态只取决于第 i - 1 行。

    如何判断上一行状态和现在这一行状态是否冲突?

    利用与运算,1&1=1,1&0=0,0&1=0,0&0=0,

    如果种植起冲突的话,与运算结果为1,所以为0的时候可以种植啦。

    如何判断当前位置/当前状态可行?

    上下判断:是0表示可以种植并;左右判断:左右为0

    将该行所代表的二进制数101010这样的形式左移或者右移,再和上面的步骤一样,利用与运算进行判断即可。

        for(int i=0; i<(1<<m); i++) //总状态数
        {
            int z=(i&(i<<1))==0;//左移判断该状态是否满足
            int y=((i&(i>>1))==0);//右移...
            book[i]=(z&&y);
            //or book[i]=((i&(i<<1))==0)&&((i&(i>>1))==0);
        }

    表示每一行的状态:

    因为只有0、1,所以可以考虑从二进制入手;

    把每一行看作是一个二进制数,则这个数就代表这一行的状态。

    dp[i][j]:代表第 i 行的状态是 j。

    注意:由于符号优先级问题,不确定优先级的请一律加上括号

    AC代码:(代码里有具体解析)

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<vector>
    using namespace std;
    
    const int N=15;
    const int mod=100000000;
    int n,m,a[N][N],dp[N][1<<N];
    int h[N];//每一行空地的状态
    int book[1<<N];//标记每个状态是否满足要求
    
    int main()
    {
        cin>>n>>m;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                cin>>a[i][j];
                h[i]=(h[i]<<1)+a[i][j];//处理每一行状态,变成二进制状态,0也要处理
            }
        }
        //左右判断
        for(int i=0; i<(1<<m); i++) //总状态数
        {
            int z=(i&(i<<1))==0;//左移判断该状态是否满足
            int y=((i&(i>>1))==0);//右移...
            book[i]=(z&&y);
            //or book[i]=((i&(i<<1))==0)&&((i&(i>>1))==0);
        }
        dp[0][0]=1;
        for(int i=1; i<=n; i++)
        {
            for(int j=0; j<(1<<m); j++)//枚举第i行的每一个状态(列)
            {
                if(book[j]&&(j&h[i])==j)//状态可行and该位置是0可以种植
                {
                    for(int k=0; k<(1<<m); k++)//不是j,枚举上一行的状态
                    {
                        if((k&j)==0)//不冲突
                            dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;
                    }
                }
            }
        }
        int ans=0;
        for(int i=0; i<(1<<m); i++)
            ans=(ans+dp[n][i])%mod;//答案加起来
        cout<<ans<<endl;
        return 0;
    }

      

  • 相关阅读:
    MVC4新功能...压缩和合并js文件和样式文件
    如何将sqlserver表中的数据导出sql语句或生成insert into语句 [转]
    利用svn自动同步更新到网站服务器 -- 网摘
    找不到方法: Int32 System.Environment.get_CurrentManagedThreadId() .
    C# .NET ASP.NET 其中关系你了解多少
    SQL语句分享[不定期更新]
    云平台概念学习
    【转】用户画像和用户档案的区别
    【转】外行杂谈论—聊聊看板 vs 大屏的区别
    【转】从信息、能量、物质的角度揭示生命真相
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12514459.html
Copyright © 2020-2023  润新知