问题如下:
编写一个程序,确定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个整数向量left
和right
,每个向量的大小为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
答案 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;
}