zoukankan      html  css  js  c++  java
  • C++ 洛谷 P1879 [USACO06NOV]玉米田Corn Fields

    没学状压DP的看一下

    合法布阵问题 

    P1879 [USACO06NOV]玉米田Corn Fields

    题意:给出一个n行m列的草地(n,m<=12),1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法。

    分析:假如我们知道每行都有x种合法放法(也就是x种状态),所以对于第i行就有x种放法,那么对于第i+1行的每种放法就有对应的x种放法。

    所以定义dp[i][j]表示第i行状态为j时的方法数(j=0,j<=x;j++),有转移方程:dp[i][j]=sum(dp[i-1][k]) k表示i-1行的状态(k=0,k<=x;k++)。

    然而,动归方程想出来了还远远不够……/*orz_wa*/

    1、预处理第i行的草地map[i],用一个二进制数表示,1表示不能放,0表示可以放。如map[1]=15,转成二进制数就是01111,就说明是 放,不放,不放,不放,不放。二进制的神奇!!!

    (常理应该是1能放 0不能放,具体原因等下就知道了,主要是方便位运算)。

    2、预处理第i行符合条件(不相邻)的状态st[i],每行共有(1<<m)-1种状态(一个点2种,二个点4种,三个点8种……)。(i=1;i<=(1<<m)-1;i++)

    但是很多是相邻的,怎么判断某一状态是否相邻:i&(i<<1)

    3、怎么处理肥沃贫瘠问题呢,对于第i行的地形map[i]和某一状态st[k],如果map[i]&st[k]>=1(如map[2]=10010,st[2]=01110,那么map[2]&st[2]=00010=2>1,所以重复了,关键:同1为1,否则为0)即说明出现了放到贫瘠草地的情况

    4、对于第i行不和i-1行相邻,st[i]&st[i-1]>=1,同上(3)即不满足(转换为st[i]&st[i-1]==0),st[i]是第i行的状态,st[i-1]是i-1行的状态

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int mod=100000000;
    int n,m;
    int st[1<<12],map[1<<12];//分别表示每一行的状态和草地的状态
    int dp[15][1<<12]; 
    int main()
    {
        scanf("%d%d",&n,&m);
        int x;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&x);
                if(x==0)map[i]=map[i]|(1<<j-1);
            }
        int k=0;         
        for(int i=0;i<=(1<<m)-1;i++)//计算每行合法的放置方式 
        {
            if(!(i&(i<<1)))st[++k]=i;
        }
        for(int i=1;i<=k;i++)//特判第一行 
        {
            if(!(st[i]&map[1]))dp[1][i]=1;
        }
        for(int i=2;i<=n;i++) //列举每一行(除了第一行) 
        {
            for(int j=1;j<=k;j++)  //每行可能情况 
            {
                if(!(map[i]&st[j]))   //符合土地肥沃贫瘠 
                for(int r=1;r<=k;r++)   //i-1行的情况 
                {
                    if(!(map[i-1]&st[r]))  // i-1行r状态符合土地肥沃贫瘠 
                    {
                        if(!(st[j]&st[r])) // i行j状态和i-1行r状态是否相邻 
                        dp[i][j]+=dp[i-1][r];   //加方案数量 
                    }
                } 
            }
        }
        int ans=0;
        for(int i=1;i<=k;i++)
        
        {
            ans=(ans+dp[n][i])%mod;   //答案?? 
        }
        printf("%d",ans);
        return 0;
    }

     总结:确定状态,从一维转向二维……(做多了就有经验,from_Mr.Li)

     提升版(P2704 [NOI2001]炮兵阵地)

    上题题解

  • 相关阅读:
    突然又想起了这首诗
    安装使用Androidx86打造快速流畅的Aandroid开发环境!
    解决电脑没插网线虚拟机无法桥接到主机
    使用WordPress更新通知服务,让搜索引擎知道你更新了,加快收录。
    php+apache+mysql环境配置时apache服务不能开启的解决
    WordPress备份的七种办法
    怎么在网站中正确使用JQuery代码
    如何让自己的博客在各搜索引擎中被搜索出来与快速收录
    轻松查看文件被哪个进程使用
    解密QQ非会员漫游聊天记录
  • 原文地址:https://www.cnblogs.com/mzyczly/p/10883799.html
Copyright © 2011-2022 走看看