• 【状压基础题】poj3254 Corn Fields


     

     

     

    题目大意 :农夫约翰有n*m块地,其中一些地荒掉了。玉米是一种傲娇的植物,种在相邻的地里会导致不孕不育。求所有种法数对100000000求余。

    读入:第一行一个n一个m,

    接下来是一个n行m列的矩形,表示田地的状态(1表示可种植,0表示不可种植)

    输出:一个整数,表示总的方法数 % 1000000000的结果

    首先我们把原图的每一行转成二进制数存储(此处及以下原图均指读入的田地状况),1表示可以种植,0表示不能种植
    以行为阶段,对于每一行,我们把可以种的标记为1,不能种则标记为0
    分析同一行中,我们由题目可以知道,两个1肯定不相邻,
    我们想把当前状态左移1位再与原数相&,若结果不为0,则肯定有两个1相邻了
    但是同样我们要注意的是,两行之间相邻也是不允许的
    例如:
    0001010
    0001001
    第一行第4个位置为1,下一行第4个位置仍为1,上下两个1相邻了,这样也是不允许的
    这样我们设一个状态为k,由状态k转移到状态j,若j&k!=0,则出现了上下两个1相邻,这样是不符合的
    接着我们必须符合原图,也就是原图中不能种的地方我们一定不能种,原图中不能种的地方为0,能种的地方为1
    但是比较麻烦的是,原图能种的地方我们不一定种,原图不能种的地方,在我们的状态中可能种,我们没办法区分这两种情况
    那么我们试着翻转一下操作
    存原图时,我们用0表示能种,1表示不能种(最初我们用1表示能种,0表示不能种)
    这样我们可以直接相&,若出现了1,则一定不能种。因为此时我们标记为1的位置,按照题目要求,在原图中一定要标记为0,如果某个位置我们种了而原图中
    不能种,那么相&得到的就是1,这样是不行的。问题就解决了。
    然后我们可以以非常显然的方式得到dp数组
    f[i, j]表示在第i行(i为一个m位的二进制数),状态为j时,所有的种法,这样得到的状态转移方程就是:
    f[i, j] = Σf[i - 1, k]( j & k == 0 && j & a[i] == 0 && k & a[i - 1] == 0)
    初态:f[0, 0] = 1;
    目标:Σ{f[n, i]}(i为m位二进制数,0 <= i < 1 << m)

     1 #include<iostream>
     2 #include<iomanip>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<ctime>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<cstdlib>
     9 #define ll long long
    10 using namespace std;
    11 const int mod = 100000000;
    12 int n, m, h;
    13 ll f[13][1 << 13], ans = 0;
    14 ll a[13];
    15 
    16 inline int read() {
    17     int  x = 0, y = 1;
    18     char ch = getchar();
    19     while(!isdigit(ch)) {
    20         if(ch == '-') y = -1;
    21         ch = getchar();
    22     }
    23     while(isdigit(ch)) {
    24         x = (x << 1) + (x << 3) + ch - '0';
    25         ch = getchar();
    26     }
    27     return x * y;
    28 }
    29 
    30 int main() {
    31     n = read(), m = read();
    32     for(int i = 1; i <= n; ++i)
    33         for(int j = 1; j <= m; ++j) {
    34             h = read();
    35             a[i] <<= 1;
    36             a[i] += (h == 0) ? 1 : 0;
    37         }
    38     f[0][0] = 1;
    39     for(int i = 1; i <= n; ++i) 
    40         for(int j = 0; j < 1 << m; ++j) {
    41             if(j & (j << 1) || j & a[i]) continue;
    42             for(int k = 0; k < 1 << m; ++k) {
    43                 if(j & k || k & a[i - 1] || k & (k << 1)) continue;
    44                 f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
    45             }
    46         }
    47     for(int i = 0; i < 1 << m; ++i)
    48         ans = (ans + f[n][i]) % mod;
    49     cout << ans << '
    ';
    50     return 0;
    51 } 

     

  • 相关阅读:
    为Mac Terminal设置代理
    Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo
    vue.js环境搭建
    nodejs实现的简单接口
    Runtime
    iOS -- 神战
    前端视频
    iOS-- 重要的链接
    Oracle 11g R2安装手册(图文教程)For Windows
    undo_retention:确定最优的撤销保留时间
  • 原文地址:https://www.cnblogs.com/ywjblog/p/9243436.html
Copyright © 2020-2023  润新知