计算5 * n板的正确配置(动态编程,C ++)

时间:2015-05-11 17:40:33

标签: c++ debugging dynamic-programming

问题如下: 编写一个程序,确定m方格上白/黑图案的数量(模5*n),不包含任何p禁止图案。

输入数据具有以下格式:第一行包含3个以逗号分隔的整数: n - 列数,p - 禁止模式数量,m - 模数。以下3*p行包含3个字符的长字符串,其中包含.x,其中.表示白色字段,x表示黑色字段。这些是禁止的模式,例如:

x..
..x
.xx

这是我解决此问题的动态算法:

让3列“块”由15位长的位集表示,其中位映射到列如下(1 ==黑色,0 ==白色):

0 5 10
1 6 11
2 7 12
3 8 13
4 9 14

读取输入数据并构造表示禁止模式的所有位集(未使用的字段设置为0)。创建一个bool向量,并在每个索引下使用等于禁止模式的二进制表示将值设置为true。对表示禁止模式的索引执行相同操作,向左移位1和2(因为禁止模式可能在列的第一行,第二行或第三行中开始)。

现在,创建2个整数向量leftright,每个向量的大小为1024(2 ^ 10)。这些向量中的索引表示2列“块”的配置。在第i次迭代中,left向量中的值表示具有由第(i-1)列中的该向量的索引表示的2列模式的板的多少不同的正确配置。现在遍历第3列的所有32种可能性,并将该列添加到2列模式,每次检查这样的3列模式是否不包含禁止模式。如果是,则跳到第3列的下一个可能性,如果它不是从表示3列模式的前2列的left向量中获取值,并将其添加到{3的列的字段中{1}}向量表示由第2列和第3列组成的2列模式。在考虑了所有可能的2列之后,交换向量,将right向量初始化为0并重复该过程,直到我们到达right列。

答案是左矢量中所有字段的总和(因为上一次操作交换了矢量)。

我希望这很清楚,如果需要澄清,请发表评论。

只有当禁止的模式在顶行和底行中至少有1 x时,我的实现才会返回正确的结果,即:

n-th

我无法弄清问题是什么。如果代码中的任何内容不清楚,请告诉我,我将编辑此帖以澄清这一点。

这是我的实施: http://pastebin.com/2ZPjiyuj

x..
...
..x

1 个答案:

答案 0 :(得分:1)

我自己设法解决了这个问题(尽管PaulMcKenzie非常感谢你让我朝着正确的方向前进)。

问题是我的算法没有区分左移0,1或2位的禁止模式。当输入数据只有底部和顶部行至少包含1个x的图案时,一切都很好,但是一旦只给出了顶部或底部行中只有.x的图案,那么程序开始行为不端。

考虑在顶行中没有任何x的禁止模式 - 将其向左移1位后,该模式的前两行变为零。我程序中最里面的循环ifs之一将被测试的模式的前2行设置为零并比较forbidden_​​patterns向量的剩余部分,其中它可以与其中一个模式匹配顶行中的任何x向左移1位!这在逻辑上是错误的,因为已经向左移位1位的禁止模式在第2行开始,而顶部两行归零的模式只能包含从第3行开始的禁止模式。这导致我的程序更频繁地进入最里面的循环,因此"计数不足"正确的配置。

对此的解决方案非常简单 - 将forbidden_​​patterns向量拆分为3个向量 - 1包含没有任何移位的模式,1包含向左移动1的模式,第3个包含向左移动2的模式。然后在最里面的循环中使用适当的向量。

固定代码: http://pastebin.com/WCb8eB9F

#include <iostream>
#include <vector>
#include <bitset>
#include <stdio.h>

using namespace std;

inline bitset<15> make_pattern()
{
  char field;
  bitset<15> pattern;

  for( uint32_t offset = 0; offset < 3; offset++ )
  {
    cin >> field;
    if( field == 'x' ) pattern.set(offset);

    cin >> field;
    if( field == 'x' ) pattern.set(offset + 5);

    cin >> field;
    if( field == 'x' ) pattern.set(offset + 10);
  }
  return pattern;
}

int main()
{
  uint32_t n, m, p;
  cin >> n;
  cin >> p;
  cin >> m;

  vector<bool> top_forbidden_patterns( 32768 ); // top_forbidden patterns can only be compared to 3 column patterns that have the top 2 rows zeroed.
  vector<bool> mid_forbidden_patterns( 32768 ); // mid_forbidden patterns can only be compared to 3 column patterns that have the top and bottom row zeroed.
  vector<bool> bottom_forbidden_patterns( 32768 ); // bottom_forbidden patterns can only be compared to 3 column patterns that have the bottom 2 rows zeroed.

  for( uint32_t i = 0; i < p; i++ )
  {
    auto pattern = make_pattern();
    bottom_forbidden_patterns[pattern.to_ulong()] = true;  // true := forbidden; false := allowed.
    mid_forbidden_patterns[(pattern << 1).to_ulong()] = true;
    top_forbidden_patterns[(pattern << 2).to_ulong()] = true;
  }

  //bitmasks for setting 2 rows of a 3 column pattern to 0;
  bitset<15> bottom_rows_reset_mask;
  bottom_rows_reset_mask.set(3); bottom_rows_reset_mask.set(8); bottom_rows_reset_mask.set(13);
  bottom_rows_reset_mask.set(4); bottom_rows_reset_mask.set(9); bottom_rows_reset_mask.set(14);
  bottom_rows_reset_mask = ~bottom_rows_reset_mask;

  bitset<15> top_rows_reset_mask;
  top_rows_reset_mask.set(0); top_rows_reset_mask.set(5); top_rows_reset_mask.set(10);
  top_rows_reset_mask.set(1); top_rows_reset_mask.set(6); top_rows_reset_mask.set(11);
  top_rows_reset_mask = ~top_rows_reset_mask;

  bitset<15> top_and_bottom_reset_mask;
  top_and_bottom_reset_mask.set(0); top_and_bottom_reset_mask.set(5); top_and_bottom_reset_mask.set(10);
  top_and_bottom_reset_mask.set(4); top_and_bottom_reset_mask.set(9); top_and_bottom_reset_mask.set(14);
  top_and_bottom_reset_mask = ~top_and_bottom_reset_mask;

  vector<uint32_t> left( 1024, 1 );
  vector<uint32_t> right( 1024, 0 );

  for( uint32_t column = 3; column <= n; column++ )
  {
    for( uint32_t first_2_columns = 0; first_2_columns < 1024; first_2_columns++ )
    {
      if( left[first_2_columns] == 0 ) continue;
      for( uint32_t third_column = 0; third_column < 32; third_column++ )
      {
        bitset<15> t_patt = (first_2_columns | third_column << 10) & top_and_bottom_reset_mask.to_ulong();
        if( mid_forbidden_patterns[t_patt.to_ulong()] == true )
          continue;

        t_patt = (first_2_columns | third_column << 10) & bottom_rows_reset_mask.to_ulong();
        if( bottom_forbidden_patterns[t_patt.to_ulong()] == true )
          continue;

        t_patt = (first_2_columns | third_column << 10) & top_rows_reset_mask.to_ulong();
        if( top_forbidden_patterns[t_patt.to_ulong()] == true )
          continue;

        t_patt = first_2_columns | third_column << 10;
        auto next_2_column_pattern = (t_patt >> 5).to_ulong();
        right[next_2_column_pattern] = (right[next_2_column_pattern] + left[first_2_columns]) % m;
      }
    }
    left.swap(right);
    right.assign(1024, 0u);
  }
  uint32_t sum = 0;
  for( auto el : left )
    sum = (sum + el) % m;

  cout << sum;
  return 0;
}