从二进制矩阵中划掉坏线
Posted
技术标签:
【中文标题】从二进制矩阵中划掉坏线【英文标题】:Crossing out bad lines from the binary matrix 【发布时间】:2014-03-06 17:25:36 【问题描述】:我们得到一个边为 n 的二元方阵。 我们会将任何包含至少一个 0 的行或列视为“坏”。 任务是取消所有错误的行和列。 任务需要使用 O(1) 的额外内存。
1 1 0 0 0 0
1 1 1 => 1 0 0
1 0 1 0 0 0
困难的是,当我们在遍历过程中发现坏行时,我们不能取消它们(否则我们总是会得到归零的矩阵)。所以我正在寻找这样的数据结构或这样的数据表示方式,以便在算法遍历矩阵时存储有关坏行和列的所有信息。
【问题讨论】:
我认为我们必须坚持二进制,我们不能将单元格设置为 0 或 1 之外的任何其他值,对吗? 我不知道这个问题是关于什么的。我们可以使用什么样的操作来解决这个问题? @NiklasB。对不起,我没有得到你的问题。我们可以以任何我们想要的方式改变矩阵的内容。我们必须记住,单元格大小为 1 位,任何包含 0 的行(行或列)都应该变成全零的行。我相信,有问题的例子是不言自明的。 @wf34:我相信不是,因为它没有向我解释。 很确定这是***.com/questions/10840044/…的副本,在那里查看我的答案。 【参考方案1】:实际上我们只需要 2n 位就可以得到答案:我们需要知道每一行和每一列是好 (1) 还是坏 (0)。每个单元格中的答案将是行和列答案的乘积。
让我们将大部分信息存储在矩阵本身中: 我们可以使用第一行来保存所有列的记录(0 或 1),但首先, 第一列保存除第一行之外的所有行的记录,我们还需要两个位来保存第一行和第一列的记录。
首先我们得到这两个额外的位(检查第一行和第一列)。
然后查找并存储其他行和列的记录。
然后计算除第一行和第一列之外的所有矩阵中的结果位。
最后:如果第一行是坏的,则应该取消它,否则保持原样,第一列也是如此。
【讨论】:
【参考方案2】:第一步,在网格中查找 0。如果我们找不到,我们就完成了。
如果我们找到一个,我们知道我们应该取消 0 的行和列中的所有 1。
因此,由于我们知道所有这些单元格的最终值,我们可以使用该行和列作为临时布尔标志来判断同一行或同一列是否包含任何 0。
具体流程:
查看矩阵找到一个 0。 跟踪找到的 0 的坐标。 循环遍历每一行和每一列,检查该行或列是否包含 0,并适当地设置标志。 然后再次循环遍历矩阵,对于不在标志行或列中的每个 1,检查是否设置了行标志或列标志,如果是,则将该 1 设置为 0。 然后将作为标志的行和列中的所有单元格设置为 0。这在线性时间(O(mn),m 行和 n 列)和 O(1) 空间中运行。
示例:
输入:
1 1 0 1 0
1 1 1 0 1
1 0 1 1 1
1 1 1 1 1
1 1 1 1 1
然后我们寻找一个零,假设我们找到了中间的一个。
然后我们用顶行中间列作为标志,判断同一行/列是否包含0:
0 1 0 1 1
1
1
0
0
然后,如果设置了标志行/列,我们会遍历将 1 设置为 0 的其他单元格:
0 0 0 0
0 0 0 0
1 0 0 0
1 0 0 0
然后我们将标志行和列设置为0:
0 0 0 0 0
0
0
0
0
然后我们有我们的最终输出:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 0 0 0 0
1 0 0 0 0
这显然是就地完成的,为了清楚起见,我只是在视觉上将其分开。
【讨论】:
【参考方案3】:我用 Natalya Ginzburg 的有用回答编写了 C++ 实现。
只是把它留在这里,以防它对某人有用。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
class Matrix
public:
Matrix(int n):
side(n),
stride( round(n/8+1) ),
is0RowGood(true),
is0ColGood(true)
printf("%d %d\n", side, stride);
data = new char[stride*side];
memset(data, 0, stride*side*sizeof(char) );
if( !data )
printf("alloc problem\n");
exit(1);
fill();
print();
~Matrix()
if(data)
delete data;
void process()
for( int j = 0; j < side; ++j )
if(getEl(0, j) == false)
is0RowGood = false;
break;
for( int i = 0; i < side; ++i )
if(getEl(i, 0) == false)
is0ColGood = false;
break;
for( int i = 1; i < side; ++i )
for( int j = 1; j < side; ++j )
if(!getEl(i,j))
setEl(i,0, false);
break;
for( int j = 1; j < side; ++j )
for( int i = 1; i < side; ++i )
if(!getEl(j,i))
setEl(0, i, false);
break;
// nullify now
for( int i = 1; i < side; ++i )
for( int j = 1; j < side; ++j )
if( !getEl(0,j) || !getEl(i,0) )
crossRow(i);
crossCol(j);
if(!is0RowGood)
crossRow(0);
if(!is0ColGood)
crossCol(0);
printf("--\n");
print();
private:
void crossRow(int x)
for(int i = 0; i < side; ++i )
setEl(x, i, false);
void crossCol(int x)
for(int i = 0; i < side; ++i )
setEl(i, x, false);
void print()
for( int i = 0; i < side; ++i )
for( int j = 0; j < side; ++j )
printf(" %d ", getEl(i,j));
printf("\n");
void fill()
for( int i = 0; i < side; ++i )
for( int j = 0; j < side; ++j )
usleep(15);
setEl(i, j, (rand() % 30 == 0) ? 0 : 1);
bool getEl(int i, int j)
int offset = trunc(i/8) + j*stride;
char byte = data[offset];
return byte & static_cast<char>(pow(2, i%8));
bool setEl(int i, int j, bool val)
int offset = trunc(i/8) + j*stride;
if(val)
data[offset] |= static_cast<char>(pow(2, i%8));
else
data[offset] &= static_cast<char>(255-pow(2, i%8));
bool is0RowGood;
bool is0ColGood;
char* data;
int side;
int stride;
;
int
main( int argc,
const char** argv )
if(argc < 2)
printf("give n as arg\n");
exit(1);
time_t t;
if(argc == 3)
t = atoi(argv[2]);
else
t = time(NULL);
printf("t=%d",t);
srand (t);
int n = atoi( argv[1] );
printf("n=%d\n",n);
Matrix m(n);
m.process();
【讨论】:
以上是关于从二进制矩阵中划掉坏线的主要内容,如果未能解决你的问题,请参考以下文章