【转载】UVa 11464 Even Parity 偶数矩阵

题意:给你一个n*n的01矩阵,让你把这个矩阵中尽量少的0转换成1,使得矩阵每个位置的上下左右四个相邻的数加起来能被2整除,求最少的转换数

首先,n 的规模并不大,最大只有15。但是完全枚举整个矩阵显然是不可能的(2225 ≈ 5 * 1067)。但是我们可以枚举第一行,然后用第一行来算出后面的所有行。

但是,怎么算呢?

先来说下算法。对于每一行,我们通过他上面的两行来决定他的值。如果上面两行得到值为奇数,那么这一行就赋值为 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
     

按照上述方法,可以计算出第三行,来完成这个例子的答案:

0 1 0
1 0 1
0 1 0

最后在说一下枚举第一行的 2 种方法,第一个种自然是直接深度优先搜索(DP)直接进行枚举。第二种可以利用位运算(末尾附上的AC代码采用的方法)进行枚举。因为整数在内存中是用二进制存储的。只要让 s 从 0 开始一直加到 2n-1 – 1 这么大就可以枚举所有的情况。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 20 + 5;
 6 const int INF = (1 << 30) - 1;
 7 int a[N][N], dp[N][N],n;
 8
 9 int deal(int s){
10     memset(dp, 0, sizeof(dp));
11     for(int c = 0; c < n; c++){
12         if(s & (1 << c)) dp[0][c] = 1;
13         else if(a[0][c] == 1) return INF;
14     }
15     for(int r = 1; r < n; r ++){
16         for(int c = 0; c < n; c ++){
17             int sum = 0;
18             if(r > 1) sum += dp[r-2][c];
19             if(c > 0) sum += dp[r-1][c-1];
20             if(c < n) sum += dp[r-1][c+1];
21             dp[r][c] = sum % 2;
22             if(dp[r][c] == 0 && a[r][c] == 1)return INF;
23         }
24     }
25     int ret = 0;
26     for(int r = 0; r < n; r ++)
27         for(int c = 0; c < n; c ++)
28             if(a[r][c] != dp[r][c])  ret++;
29     return ret;
30 }
31
32
33 int main(){
34     int T;
35     scanf("%d", &T);
36     for(int cas = 1; cas <= T; cas ++){
37         scanf("%d", &n);
38         for(int r = 0; r < n; r ++)
39             for(int c = 0; c < n; c ++)
40                 scanf("%d", &a[r][c]);
41         int ans = INF;
42         for(int s = 0; s < (1 << n); s ++)
43             ans = min(ans, deal(s));
44         printf("Case %d: %d\n", cas, ans == INF ? -1 : ans);
45     }
46     return 0;
47 }
时间: 2024-08-25 05:11:50

【转载】UVa 11464 Even Parity 偶数矩阵的相关文章

uva 11464 Even Parity(逐层递推)

uva 11464 Even Parity We have a grid of size N x N. Each cell of the grid initially contains a zero(0) or a one(1). The parity of a cell is the number of 1s surrounding that cell. A cell is surrounded by at most 4 cells (top, bottom, left, right). Su

枚举 UVA 11464 Even Parity

题目传送门 1 /* 2 题意:求最少改变多少个0成1,使得每一个元素四周的和为偶数 3 枚举:枚举第一行的所有可能(1<<n),下一行完全能够由上一行递推出来,b数组保存该位置需要填什么 4 最后检查不同的数量,取最小值 5 */ 6 #include <cstdio> 7 #include <algorithm> 8 #include <cstring> 9 using namespace std; 10 11 const int MAXN = 20;

UVA 11464 Even Parity(枚举递推)

11464 - Even Parity Time limit: 3.000 seconds We have a grid of size N x N. Each cell of the grid initially contains a zero(0) or a one(1). The parity of a cell is the number of 1s surrounding that cell. A cell is surrounded by at most 4 cells (top,

UVa 11464 Even Parity

题意:给出n*n的01矩阵,将尽量少的0变成1,使得每个元素的上下左右的元素的和为偶数 看的白书的思路,二进制枚举第一行,再依次算出改变元素的个数, 自己写的时候发现这里不会写,“每个元素的上下左右的元素” 大概就是这个意思 真是太捉急了的说-----------5555 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<s

UVA 11464 - Even Parity 状态压缩,分析 难度: 2

题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2459 题意 N*N 的01方阵,可用操作为把任意0变为1,求操作的最小次数,使得任意位置的上下左右之和(不包含自身)为偶数 思路 如刘书,关键在于状态只有第一行的2^15个. 感想 1. 忘了memset 代码 #include <algorithm> #include

【UVA】11464-Even Parity(二进制枚举子集)

枚举第一行的所有可能情况,之后根据上面行计算下面行(判断是否冲突),获得最终结果. 14058243 11464 Even Parity Accepted C++ 0.275 2014-08-18 05:14:15 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<stack> #inc

uva 11885 - Number of Battlefields(矩阵快速幂)

题目连接:uva 11885 - Number of Battlefields 题目大意:给出周长p,问多少种形状的周长为p的,并且该图形的最小包围矩阵的周长也是p,不包括矩形. 解题思路:矩阵快速幂,如果包含矩形的话,对应的则是斐波那契数列的偶数项,所以对应减去矩形的个数即可. #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const ll MOD = 9876543

UVA 1386 - Cellular Automaton(循环矩阵)

UVA 1386 - Cellular Automaton 题目链接 题意:给定一个n格的环,现在有个距离d,每次变化把环和他周围距离d以内的格子相加,结果mod m,问经过k次变换之后,环上的各个数字 思路:矩阵很好想,每个位置对应周围几个位置为1,其余位置为0,但是这个矩阵有500,有点大,直接n^3去求矩阵不太合适,然后观察发现这个矩阵是个循环矩阵,循环矩阵相乘的话,只需要保存一行即可,然后用n^2的时间就足够计算了 代码: #include <stdio.h> #include <

uva 11992 线段树对矩阵进行更新查询

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3143 把矩阵变成一行,然后计算位置,lrj给了线段树数组做法 但是我做的线段树空间过大,直接爆掉,所以换方法了 主要还是测试自己的线段树区间更新的模板 各种RE+WA之后AC,,,,, 做的时候出现的几个错误: 1.行和列弄错 2.build初始化的时候,mmin mmax 都初始化为0才对