zoukankan      html  css  js  c++  java
  • poj 3254 && 2411

    状态压缩dp,感觉还是不清晰,虽说就两种状态 0 1,但是感觉变化太多了,而且状态转移也不好想

    题目:http://poj.org/problem?id=3254

    题意:给出 N * M的图,上面只有 0 或者 1两种情况,如果是 1 表示这里可以放牛,如果是 0 表示不可以放牛,而且牛是不可以相邻的,问在这片区域内最多有多少种放牛的方案

    很简单的一个状态压缩 按给出的样例来说

    先看第一行 (1 表示该位置有牛,0 表示该位置没有牛)可以用二进制串来表示牛的放置情况

    0 0 0 (0)   0 0 1(1)  0 1 0 (2) 1 0 0(4)  1 0 1(5) 也就是题目中给的第一行最多有这五种情况,分别对应的十进制数 为 0 1 2 4 5

    第二行 

    0 0 0 (0) 0 1 0 (2)只有这两种情况,对应的数为 0 2 。当是 0 这种情况时,于第一行的每一种情况都不冲突,所以有 5种,当是第二种情况是,那么与第一行的 2 这种情况有冲突(两头牛不可一相邻)所以是四种情况,所以一共有 9种 放牛的方案

    所以预处理每一行可以放牛的情况总数,然后计算每一行时判断与上一行是否有冲突

    View Code
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <vector>
     6 #define N 100
     7 #define mod 100000000
     8 #define _clr(a,val) (memset(a,val,sizeof(a)))
     9 
    10 using namespace std;
    11 
    12 int n,m;
    13 vector<int>num[13];
    14 int dp[20][3000]; // dp [i][j] 表示 第 i 行取第 j 种方案时可行的方案数
    15 void cal(int x,int y)
    16 {
    17     for(int i = 0; i < (1 << m); i++)
    18     {
    19         if((i >> 1) & i || (i << 1) & i) continue; 
    20         if(i & y) continue; 
    21         num[x].push_back(i);
    22     }
    23 }
    24 int main()
    25 {
    26     int i,j,k;
    27     int x;
    28     //freopen("data.txt","r",stdin);
    29     while(scanf("%d%d",&n,&m) != EOF)
    30     {
    31         //_clr(num,0);
    32         for(i = 1; i <= n; i++)
    33         {
    34             num[i].clear();
    35             int tem = 0;
    36             for(j = 1; j <= m; j++)
    37             {
    38                 scanf("%d",&x);
    39                 x = 1 - x;
    40                 tem = tem * 2 + x;
    41             }
    42             cal(i,tem); // 计算 第 i 行可以放牛的各种情况
    43         }
    44         _clr(dp,0);
    45         for(i = 0; i < num[1].size(); i++)
    46         dp[1][i] = 1;
    47         for(i = 2; i <= n; i++)
    48         {
    49             for(j = 0; j < num[i].size(); j++)
    50             {
    51                 for(k = 0; k < num[i - 1].size(); k++)
    52                 {
    53                     if(num[i][j] & num[i - 1][k]) // 不为零,说明放牛有冲突,跳过
    54                     {
    55                         continue;
    56                     }
    57                     dp[i][j] += dp[i - 1][k];
    58                 }
    59             }
    60         }
    61         int ans = 0;
    62         for(i = 0; i < num[n].size(); i++)
    63         {
    64             ans = (ans + dp[n][i]) % mod;
    65         }
    66         printf("%d\n",ans);
    67     }
    68     return 0;
    69 }

    题目:http://poj.org/problem?id=2411

    题意:棋盘覆盖问题,给出一个 h * w 的棋盘,让你用 2 * 1的方块或横或竖的去覆盖棋盘,问有多少种方案数

    0:表示该格是横放或是由上一层的竖放恰好填上了

    1:表示该格竖放并且对下一行有影响

    该行的状态可以用一个2进制数来表示,如果是 1,那么下行该格一定为零,但如果为零,那么下行该格可以是 1 也可以是 0

    View Code
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <vector>
     6 #define N 20
     7 #define mod 100000000
     8 #define _clr(a,val) (memset(a,val,sizeof(a)))
     9 
    10 using namespace std;
    11 
    12 typedef long long ll;
    13 ll dp[N][3000];
    14 int h,w;
    15 int i,j;
    16 void dfs(int x,int s)  // 下层的第 x 个位置,s 为下一层的状态
    17 {
    18     if(x == w + 1) // 如果 x 是边界时,直接求出下层为状态s 的方案数,返回
    19     {
    20         dp[i + 1][s] += dp[i][j];
    21         return ;
    22     }
    23     else
    24     {
    25         if((j >> (x - 1) & 1) == 1)  // 上层为 1,下层为 0
    26         dfs(x + 1,s);
    27         else  // 上层 为 0
    28         {
    29             if(x + 1 <= w && (j >> x & 1) == 0) // 下层为 0
    30             dfs(x + 2,s);
    31             dfs(x + 1,s | (1 << (x - 1))); // 将下层该位置改为 1
    32         }
    33     }
    34 }
    35 int main()
    36 {
    37     //freopen("data.txt","r",stdin);
    38     while(scanf("%d%d",&h,&w) != EOF)
    39     {
    40         if(h == 0 && w == 0) break;
    41         if(h * w % 2)
    42         {
    43             cout<<"0\n";
    44             continue;
    45         }
    46         _clr(dp,0);
    47         dp[0][0] = 1;
    48         int temp = 1 << w;
    49         for(i = 0; i <= h; i++)
    50         {
    51             for(j = 0; j < temp; j++)
    52             {
    53                 if(dp[i][j])
    54                 dfs(1,0);
    55             }
    56         }
    57         printf("%I64d\n",dp[h][0]);
    58     }
    59     return 0;
    60 }
  • 相关阅读:
    冲刺第二阶段第十天
    冲刺第二阶段第九天
    冲刺第二阶段第八天
    冲刺第二阶段第七天
    第十三周学习进度条
    冲刺第二阶段第六天
    第二冲刺阶段绩效评估
    Beta版总结会议
    Alpha版总结会议
    第二次冲刺阶段站立会议(十)
  • 原文地址:https://www.cnblogs.com/fxh19911107/p/2636638.html
Copyright © 2011-2022 走看看