n * n矩阵,4邻域和为偶数,否则0->1,求变换次数
对于每一行,我们通过他上面的两行来决定他的值.如果上面两行得到值为奇数,那么这一行就赋值为1,否则赋值为 0。
然后与原始矩阵比较,如果是由 1 变 0 那么这种情况是不允许的,于是继续枚举第一行,重新计算后面的。如果是
由 0 变 1(或不变) 那么保存下来。最后在计算所有的格子之后,遍历一下就能统计转化数。然后取最小值就可以了。
下面用题目中给的第二组数据来演示一下如何通过上一行来计算下一行。
问题 正解
0 0 0 ==> 0 1 0
1 0 0 ==> 1 0 1
0 0 0 ==> 0 1 0
首先我们通过枚举第一行可以达到以下情况
0 1 0
通过第一行来计算第二行,对于 x 所在的这一格来说,把这一格当做他上面一格的下面相邻的格子进行计算,
于是对于第一行第一列来说,他上下左右相加起来为 1 + x,因为要保证是偶数,所以 x = 1。接着与原矩阵
进行比较,是符合题目要求的转化(不变)。保留,继续计算下一个
0 1 0
x
计算第二行第二列,按照上面的方法,计算得出 0 + 0 + x 要为偶数,所以 x = 0。与原数组比较依旧是符合题目要求的。
0 1 0
1 x
计算第二行第三列,同上,得出 1 + x 要为偶数,所以 x = 1。与原矩阵比较,发现是符合要求的转化(0 变 1)继续。
0 1 0
1 0 x
第二行就得出来了,是下面这种情况
0 1 0
1 0 1
枚举第一行的2种方法,第一个种自然是直接深度优先搜索(DP)直接进行枚举。第二种可以利用位运算进行枚举。因为
整数在内存中是用二进制存储的。只要让 s 从 0 开始一直加到 2^(n-1)–1 这么大就可以枚举所有的情况。
bool val(int i, int j) {
int sum = 0;
if ( i < 1 ) return false;
int row = i - 1, col = j;
// 左
if ( col >= 1 ) sum += matrix[row][col-1];
// 上
if ( row >= 1) sum += matrix[row-1][col];
// 右
if ( col < n-1 ) sum += matrix[row][col+1];
return (sum % 2);
}
int main () {
// 遍历第一行所有情况, 共n^2次
// 顺便利用位运算解决n层嵌套循环
int min = n*n;
for ( int i = 2; i < n*2; i++ ) {
int sum = 0;
for ( int col = 0; col < n; col ++ ) {
matrix[0][col] = ( i >> col ) % 2 ;
sum += matrix[0][col];
}
for ( int row = 1; row < n; row ++ ) {
for ( int col = 0; col < n; col ++ ) {
matrix[row][col] = val(row, col);
sum += matrix[row][col];
}
}
if ( sum < min ) {
min = sum;
memcpy(minMt, matrix, sizeof(matrix));
}
}
printf("%d\n", min);
for ( int row = 0; row < n; row ++ ) {
for ( int col = 0; col < n; col ++ ) {
printf("%d ", minMt[row][col]);
}
printf("\n");
}
system("PAUSE");
return 0;
}
浙公网安备 33010602011771号