我需要用零填充数组,但有以下假设:
0
和1
0
更改为1
,将1
更改为0
1
时,我们必须将其更改为0
,以便其邻居也会更改,例如,对于如下所示的数组:1 0 1 1 1 1 0 1 0
当我们改变(1,1)处的元素时,我们就得到了这样的数组:
1 1 1 0 0 0 0 0 0
1
更改为0
以将数组清零的次数1)第一个例子,数组如下所示:
0 1 0 1 1 1 0 1 0
答案是1。
2)第二个例子,数组如下所示:
0 1 0 0 0 0 0 0 1 1 1 0 1 0 1 0 0 0 1 1 0 1 1 1 1 1 0 1 1 1 0 0 1 0 1 1 1 0 1 0 0 1 0 1 0 1 0 0
答案是10.
也可能存在无法将阵列归零的情况,那么答案应该是“不可能的”#34;。
不知怎的,我无法正常工作:对于第一个例子,我得到了正确答案(1)但是对于第二个例子,程序说impossible
而不是10。
我的代码中有什么错误?
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
int n,m;
cin >> n >> m;
bool tab[n][m];
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
cin >> tab[i][j];
int counter = 0;
for(int i=0; i<n-1; i++)
{
for(int j=0; j<m-1; j++)
{
if(tab[i][j] == 1 && i > 0 && j > 0)
{
tab[i-1][j] = !tab[i-1][j];
tab[i+1][j] = !tab[i+1][j];
tab[i][j+1] = !tab[i][j+1];
tab[i][j-1] = !tab[i][j-1];
tab[i][j] = !tab[i][j];
counter ++;
}
}
}
bool impossible = 0;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(tab[i][j] == 1)
{
cout << "impossible\n";
impossible = 1;
break;
}
}
if(impossible)
break;
}
if(!impossible)
cout << counter << "\n";
return 0;
}
答案 0 :(得分:5)
我相信你的程序在6x8矩阵中返回不可能的原因是因为你一直在以从左到右/从上到下的方式遍历,用0替换你遇到的每个1的实例虽然这似乎是正确的解决方案,但它所做的只是通过修改它的相邻值来分散矩阵周围的1和0。我认为解决这个问题的方法是从下到上/从右到左开始并将1s推向第一行。在某种程度上转弯(捕捉)它们直到它们被消除。
无论如何,这是我解决这个问题的方法。我不完全确定这是否是您要追求的,但我认为它可以完成您提供的三个矩阵的工作。代码不是很复杂,用一些更难的问题来测试代码是否真的有用。
#include <iostream>
static unsigned counter = 0;
template<std::size_t M, std::size_t N>
void print( const bool (&mat) [M][N] )
{
for (std::size_t i = 0; i < M; ++i)
{
for (std::size_t j = 0; j < N; ++j)
std::cout<< mat[i][j] << " ";
std::cout<<std::endl;
}
std::cout<<std::endl;
}
template<std::size_t M, std::size_t N>
void flipNeighbours( bool (&mat) [M][N], unsigned i, unsigned j )
{
mat[i][j-1] = !(mat[i][j-1]);
mat[i][j+1] = !(mat[i][j+1]);
mat[i-1][j] = !(mat[i-1][j]);
mat[i+1][j] = !(mat[i+1][j]);
mat[i][j] = !(mat[i][j]);
++counter;
}
template<std::size_t M, std::size_t N>
bool checkCornersForOnes( const bool (&mat) [M][N] )
{
return (mat[0][0] || mat[0][N-1] || mat[M-1][0] || mat[M-1][N-1]);
}
template<std::size_t M, std::size_t N>
bool isBottomTrue( bool (&mat) [M][N], unsigned i, unsigned j )
{
return (mat[i+1][j]);
}
template<std::size_t M, std::size_t N>
bool traverse( bool (&mat) [M][N] )
{
if (checkCornersForOnes(mat))
{
std::cout<< "-Found 1s in the matrix corners." <<std::endl;
return false;
}
for (std::size_t i = M-2; i > 0; --i)
for (std::size_t j = N-2; j > 0; --j)
if (isBottomTrue(mat,i,j))
flipNeighbours(mat,i,j);
std::size_t count_after_traversing = 0;
for (std::size_t i = 0; i < M; ++i)
for (std::size_t j = 0; j < N; ++j)
count_after_traversing += mat[i][j];
if (count_after_traversing > 0)
{
std::cout<< "-Found <"<<count_after_traversing<< "> 1s in the matrix." <<std::endl;
return false;
}
return true;
}
#define MATRIX matrix4
int main()
{
bool matrix1[3][3] = {{1,0,1},
{1,1,1},
{0,1,0}};
bool matrix2[3][3] = {{0,1,0},
{1,1,1},
{0,1,0}};
bool matrix3[5][4] = {{0,1,0,0},
{1,0,1,0},
{1,1,0,1},
{1,1,1,0},
{0,1,1,0}};
bool matrix4[6][8] = {{0,1,0,0,0,0,0,0},
{1,1,1,0,1,0,1,0},
{0,0,1,1,0,1,1,1},
{1,1,0,1,1,1,0,0},
{1,0,1,1,1,0,1,0},
{0,1,0,1,0,1,0,0}};
std::cout<< "-Problem-" <<std::endl;
print(MATRIX);
if (traverse( MATRIX ) )
{
std::cout<< "-Answer-"<<std::endl;
print(MATRIX);
std::cout<< "Num of flips = "<<counter <<std::endl;
}
else
{
std::cout<< "-The Solution is impossible-"<<std::endl;
print(MATRIX);
}
}
matrix1 的输出:
-Problem-
1 0 1
1 1 1
0 1 0
-Found 1s in the matrix corners.
-The Solution is impossible-
1 0 1
1 1 1
0 1 0
matrix2 的输出:
-Problem-
0 1 0
1 1 1
0 1 0
-Answer-
0 0 0
0 0 0
0 0 0
Num of flips = 1
matrix3 的输出:
-Problem-
0 1 0 0
1 0 1 0
1 1 0 1
1 1 1 0
0 1 1 0
-Found <6> 1s in the matrix.
-The Solution is impossible-
0 1 1 0
1 0 1 1
0 0 0 0
0 0 0 1
0 0 0 0
输出 matrix4 (解决原始问题):
-Problem-
0 1 0 0 0 0 0 0
1 1 1 0 1 0 1 0
0 0 1 1 0 1 1 1
1 1 0 1 1 1 0 0
1 0 1 1 1 0 1 0
0 1 0 1 0 1 0 0
-Answer-
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 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Num of flips = 10
答案 1 :(得分:4)
好的,这是我的尝试有点不同。
<强>观强>
注意:我在这里假设&#34;我们无法改变第一行&#34;意味着&#34;我们无法更改 outmost 行&#34;。
一些术语:
切换一下的行为是可交换的。也就是说,我们切换它的顺序无关紧要 - 最终结果总是相同的(这是一个简单的陈述)。这意味着翻转也是一种可交换的动作,我们可以按任意顺序翻转位。
在矩阵边缘切换值的唯一方法是将其旁边的位翻转不均匀的次数。当我们正在寻找尽可能低的翻转时,我们希望最多翻转一次。因此,在如下所示的场景中,x
将需要恰好翻转一次,而y
将需要恰好翻转0次。
. .
1 x
0 y
. ,
由此我们可以得出两个结论:
矩阵的一个角永远不会被切换 - 如果找到角上的1,则无法使用任意数量的翻转使矩阵为零。因此,您的第一个示例可以被丢弃,甚至不会翻转一个位。
角落旁边的位必须与另一侧的位具有相同的值。因此,您在评论中发布的This matrix也可以在不翻转一位(右下角)的情况下被丢弃。
上述两个条件的例子:
0 1 .
0 x .
. . .
不可能,因为x
需要完全翻转和正好为零次。
0 1 .
1 x .
. . .
可能,x
需要恰好翻转一次。
<强>算法强>
我们现在可以做一个递归参数,我建议如下:
m
n
矩阵。impossible
。m - 2
按n - 2
矩阵(删除顶部和机器人行,左右列)重新启动#1 2,否则打印计数器并退出。<强>实施强>
最初我以为这会变得漂亮而漂亮,但事实上它被告知它比我原先认为的那样麻烦,因为我们必须跟踪很多指数。如果您对实施有疑问,请提出问题,但它实质上是对上述步骤的纯粹翻译。
#include <iostream>
#include <vector>
using Matrix = std::vector<std::vector<int>>;
void flip_bit(Matrix& mat, int i, int j, int& counter)
{
mat[i][j] = !mat[i][j];
mat[i - 1][j] = !mat[i - 1][j];
mat[i + 1][j] = !mat[i + 1][j];
mat[i][j - 1] = !mat[i][j - 1];
mat[i][j + 1] = !mat[i][j + 1];
++counter;
}
int flip(Matrix& mat, int n, int m, int p = 0, int counter = 0)
{
// I use p for 'padding', i.e. 0 means the full array, 1 means the outmost edge taken away, 2 the 2 most outmost edges, etc.
// max indices of the sub-array
int np = n - p - 1;
int mp = m - p - 1;
// Checking corners
if (mat[p][p] || mat[np][p] || mat[p][mp] || mat[np][mp] || // condition #1
(mat[p + 1][p] != mat[p][p + 1]) || (mat[np - 1][p] != mat[np][p + 1]) || // condition #2
(mat[p + 1][mp] != mat[p][mp - 1]) || (mat[np - 1][mp] != mat[np][mp - 1]))
return -1;
// We walk over all edge values that are *not* corners and
// flipping the bit that are *inside* the current bit if it's 1
for (int j = p + 1; j < mp; ++j) {
if (mat[p][j]) flip_bit(mat, p + 1, j, counter);
if (mat[np][j]) flip_bit(mat, np - 1, j, counter);
}
for (int i = p + 1; i < np; ++i) {
if (mat[i][p]) flip_bit(mat, i, p + 1, counter);
if (mat[i][mp]) flip_bit(mat, i, mp - 1, counter);
}
// Finished or flip the next sub-array?
if (np == 1 || mp == 1)
return counter;
else
return flip(mat, n, m, p + 1, counter);
}
int main()
{
int n, m;
std::cin >> n >> m;
Matrix mat(n, std::vector<int>(m, 0));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
std::cin >> mat[i][j];
}
}
int counter = flip(mat, n, m);
if (counter < 0)
std::cout << "impossible" << std::endl;
else
std::cout << counter << std::endl;
}
<强>输出强>
3 3
1 0 1
1 1 1
0 1 0
不可能
3 3
0 1 0
1 1 1
0 1 0
1
6 8
0 1 0 0 0 0 0 0
1 1 1 0 1 0 1 0
0 0 1 1 0 1 1 1
1 1 0 1 1 1 0 0
1 0 1 1 1 0 1 0
0 1 0 1 0 1 0 0
10
4 6
0 1 0 0
1 0 1 0
1 1 0 1
1 1 1 0
1 1 1 0
不可能
答案 2 :(得分:2)
如果tab [0] [j]为1,则必须切换制表符[1] [j]才能将其清除。然后你不能在没有清除第0行的情况下切换第1行。所以它似乎是一个减少步骤。重复该步骤,直到剩下一行。如果运气不清楚最后一行,我的直觉是它是不可能的&#34;情况下。
class d():
def __init__(self):
self._values = []
def __pos__(self):
return self._values[0]
def append(self, value): # create your won function
self._values.append(value)
答案 3 :(得分:1)
问题是这样说的:
y
yxy If you flip x, then you have to flip all the ys
y
但如果您这样想的话,这很容易:
x
yyy If you flip x, then you have to flip all the ys
y
这是同样的事情,但现在解决方案很明显 - 你必须翻转第0行中的所有1,这将翻转第1行和第2行中的一些位,然后你必须翻转第1行中的所有1,等等,直到你走到尽头。
答案 4 :(得分:1)
如果这确实是Lights Out游戏,那么有很多资源可以详细说明如何解决游戏问题。正如其他海报已经提到的那样,这很可能是Lights out game algorithm的重复。
让我们看看我们是否能解决所提供的第一个样本谜题,但至少要提出一个算法的具体描述。
最初的谜题似乎是可以解决的:
1 0 1
1 1 1
0 1 0
诀窍在于,您可以通过更改其下方行中的值来清除顶行中的1。我将使用基于1的偏移量按行和列提供坐标,这意味着左上角值为(1,1),右下角值为(3,3)。
改变(2,1),然后改变(2,3),然后改变(3,2)。我将在下一步中显示电路板的中间状态,其中*将更改电池。
1 0 1 (2,1) 0 0 1 (2,3) 0 0 0 (3, 2) 0 0 0
* 1 1 ------> 0 0 * ------> 0 1 0 ------> 0 0 0
0 1 0 1 1 0 1 * 1 0 0 0
此板可以解决,移动次数似乎为3。
伪算法如下:
flipCount = 0
for each row _below_ the top row:
for each element in the current row:
if the element in the row above is 1, toggle the element in this row:
increment flipCount
if the board is clear, output flipCount
if the board isnt clear, output "Impossible"
我希望这会有所帮助;如果需要,我可以进一步详细说明,但这是标准熄灯解决方案的核心。 BTW,它与高斯消除有关;线性代数在某些奇怪的情况下出现:)
最后,就您的代码有什么问题而言,它似乎是以下循环:
for(int i=0; i<n-1; i++)
{
for(int j=0; j<m-1; j++)
{
if(tab[i][j] == 1 && i > 0 && j > 0)
{
tab[i-1][j] = !tab[i-1][j];
tab[i+1][j] = !tab[i+1][j];
tab[i][j+1] = !tab[i][j+1];
tab[i][j-1] = !tab[i][j-1];
tab[i][j] = !tab[i][j];
counter ++;
}
}
}
我遇到了几个问题,但又是第一个假设:
如果是这种情况,则会发现以下情况:
把这些放在一起,你有:
for(int i=1; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(tab[i-1][j] == 1)
{
tab[i-1][j] = !tab[i-1][j];
if (i+1 < n)
tab[i+1][j] = !tab[i+1][j];
if (j+1 < m)
tab[i][j+1] = !tab[i][j+1];
if (j > 0)
tab[i][j-1] = !tab[i][j-1];
tab[i][j] = !tab[i][j];
counter ++;
}
}
}
答案 5 :(得分:0)
一个小类,可以作为输入文件或测试所有可能的组合,第一行只有零,在6,5矩阵上:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
typedef std::vector< std::vector<int> > Matrix;
class MatrixCleaner
{
public:
void swapElement(int row, int col)
{
if (row >= 0 && row < (int)matrix.size() && col >= 0 && col < (int)matrix[row].size())
matrix[row][col] = !matrix[row][col];
}
void swapElements(int row, int col)
{
swapElement(row - 1, col);
swapElement(row, col - 1);
swapElement(row, col);
swapElement(row, col + 1);
swapElement(row + 1, col);
}
void printMatrix()
{
for (auto &v : matrix)
{
for (auto &val : v)
{
std::cout << val << " ";
}
std::cout << "\n";
}
}
void loadMatrix(std::string path)
{
std::ifstream fileStream;
fileStream.open(path);
matrix.resize(1);
bool enconteredNumber = false;
bool skipLine = false;
bool skipBlock = false;
for (char c; fileStream.get(c);)
{
if (skipLine)
{
if (c != '*')
skipBlock = true;
if (c != '\n')
continue;
else
skipLine = false;
}
if (skipBlock)
{
if (c == '*')
skipBlock = false;
continue;
}
switch (c)
{
case '0':
matrix.back().push_back(0);
enconteredNumber = true;
break;
case '1':
matrix.back().push_back(1);
enconteredNumber = true;
break;
case '\n':
if (enconteredNumber)
{
matrix.resize(matrix.size() + 1);
enconteredNumber = false;
}
break;
case '#':
if(!skipBlock)
skipLine = true;
break;
case '*':
skipBlock = true;
break;
default:
break;
}
}
while (matrix.size() > 0 && matrix.back().empty())
matrix.pop_back();
fileStream.close();
}
void loadRandomValidMatrix(int seed = -1)
{
//Default matrix
matrix = {
{ 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,0,0 },
};
int setNum = seed;
if(seed < 0)
if(seed < -1)
setNum = std::rand() % -seed;
else
setNum = std::rand() % 33554432;
for (size_t r = 1; r < matrix.size(); r++)
for (size_t c = 0; c < matrix[r].size(); c++)
{
if (setNum & 1)
swapElements(r, c);
setNum >>= 1;
}
}
bool test()
{
bool retVal = true;
for (int i = 0; i < 33554432; i++)
{
loadRandomValidMatrix(i);
if( (i % 1000000) == 0 )
std::cout << "i= " << i << "\n";
if (clean() < 0)
{
// std::cout << "x";
std::cout << "\n" << i << "\n";
retVal = false;
break;
}
else
{
// std::cout << ".";
}
}
return retVal;
}
int clean()
{
int numOfSwaps = 0;
try
{
for (size_t r = 1; r < matrix.size(); r++)
{
for (size_t c = 0; c < matrix[r].size(); c++)
{
if (matrix.at(r - 1).at(c))
{
swapElements(r, c);
numOfSwaps++;
}
}
}
}
catch (...)
{
return -2;
}
if (!matrix.empty())
for (auto &val : matrix.back())
{
if (val == 1)
{
numOfSwaps = -1;
break;
}
}
return numOfSwaps;
}
Matrix matrix;
};
int main(int argc, char **argv)
{
std::srand(std::time(NULL));
MatrixCleaner matrixSwaper;
if (argc > 1)
{
matrixSwaper.loadMatrix(argv[argc - 1]);
std::cout << "intput:\n";
matrixSwaper.printMatrix();
int numOfSwaps = matrixSwaper.clean();
std::cout << "\noutput:\n";
matrixSwaper.printMatrix();
if (numOfSwaps > 0)
std::cout << "\nresult = " << numOfSwaps << " matrix is clean now " << std::endl;
else if (numOfSwaps == 0)
std::cout << "\nresult = " << numOfSwaps << " nothing to clean " << std::endl;
else
std::cout << "\nresult = " << numOfSwaps << " matrix cannot be clean " << std::endl;
}
else
{
std::cout << "Testing ";
if (matrixSwaper.test())
std::cout << " PASS\n";
else
std::cout << " FAIL\n";
}
std::cin.ignore();
return 0;
}