zoukankan      html  css  js  c++  java
  • 【洛谷 1879】玉米田

    题目描述
    农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
    遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
    John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
    输入格式:
    第一行:两个整数M和N,用空格隔开。
    第2到第M+1行:每行包含N个用空格隔开的整数,描述了每块土地的状态。第i+1行描述了第i行的土地,所有整数均为0或1,是1的话,表示这块土地足够肥沃,0则表示这块土地不适合种草。
    输出格式:
    一个整数,即牧场分配总方案数除以100,000,000的余数。
    输入输出样例
    输入样例:
    2 3
    1 1 1
    0 1 0
    输出样例:
    9

    解析:
    1.本题是个经典的状态压缩DP题

    2.设f[i][j]表示从首行到第i行且第i行状态为j的方案数(j表示的是二进制转化为十进制的数,从00…0到11…1的数[m个0或1]。每一个0或者1表示种了玉米和没种玉米)
    3.如果第i行和第i-1行没有冲突,且第i行左边没有相邻的1且满足贫瘠的土地上不种玉米,则f[i][j]+=f[i-1][k],j和k都表示(二进制)状态

    4.如何判断j里面有没有存在相邻的1 ?。如果s&(s<<1)>0则有,=0则无。例如1101左移一位变成11010与01101相与结果是01000。有相邻的1.但是例如1001左移一位变成10010与01001相与结果是00000。没有相邻的1.

    5.如何判断第i行和第i-1行没有冲突?如果第i行的二进制是j,i-1行的二进制是k,则判断j&k是否等于0就行了,如果等于0则不冲突,若不等于0则冲突。因为不等于0的时候必须有一对对应位两个都是1

    6.如何判断贫瘠的土地不种玉米?把每行的a[i][j]转换成二进制存到另一个F[i]数组里面去。然后判断的时候只要((j&F[i])==j)则满足条件。如果都为1,满足条件!j不会改变还是1。若都为0,满足条件!j不会改变还是0。如果是j的第k位的二进制值是1,而F[i]的第k位的二进制值为0,这时,在贫瘠的土地上种了玉米,不符合条件!此时,j会改变成0。

    7.注意细节!f[13][4100],F[4100]因为数字可以开到2的12次方4096。[查了好久才发现,为什么会WA呢……再说了数组开大不花钱(划掉)]

    8.我打字好累的!!!
    代码如下:

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int Mod=100000000;
    int m,n,f[13][4100],F[4100],a[13][13],ans;
    int main(){
        //freopen("a3254.in","r",stdin);
        //freopen("a3254.out","w",stdout);
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&a[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                F[i]=(F[i]<<1)+a[i][j];
        //把数组a[i][j]转换到F[i]二进制里面去 
        int se=1<<m;//m位的二进制 
        f[0][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<se;j++)
                if(((j&(j<<1))==0) && ((j&F[i])==j)) 
                  //如果左边没有相邻的1且满足土地条件 
                   for(int k=0;k<se;k++)
                       if((j&k)==0)//i行的j状态的i-1行的k状态不冲突 
                          f[i][j]=(f[i][j]+f[i-1][k])%Mod;//更新 
        for(int i=0;i<se;i++)
            ans=(ans+f[n][i])%Mod;//加上答案 
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Ubuntu安装Cassandra
    Ubuntu安装中文输入法
    CoreOS, Kubernetes, etcd
    CountDownLatch, CyclicBarrier and Semaphore
    Java Primitives and Bits
    vue 和 webstorm(01) 之 基本入门 _fei
    ubuntu 命令窗口背景颜色 #300a24 _fei
    2345 看图王ad介绍----关闭广告 _fei
    PHP 使用 pdo 操作oracle数据库 报错 _fei
    PHP 使用 pdo 操作oracle数据库 报错 _fei
  • 原文地址:https://www.cnblogs.com/wuhu-JJJ/p/11251581.html
Copyright © 2011-2022 走看看