给你一个 n * n 的 01 矩阵,现在你的任务是将这个矩阵中尽量少的 0 转化为 1 ,使得每个数的上下左右四个相邻的数加起来是偶数。求最少的转化个数。

首先,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 这么大就可以枚举所有的情况。具体实现可以参看我的代码。

 

附AC代码

   1: #include <stdio.h>

   2: #include <math.h>

   3: #include <iostream>

   4: #include <cstdarg>

   5: #include <algorithm>

   6: #include <string.h>

   7: #include <stdlib.h>

   8: #include <string>

   9: #include <list>

  10: #include <vector>

  11: #include <map>

  12: #define LL long long

  13: #define M(a) memset(a, 0, sizeof(a))

  14: using namespace std;

  15:  

  16:  

  17: const int MAXLEN = 19, INF = 99999999;

  18: int T, n, f;

  19: int a[MAXLEN][MAXLEN], b[MAXLEN][MAXLEN];

  20:  

  21: void Clean(int count, ...)

  22: {

  23:     va_list arg_ptr;

  24:     va_start (arg_ptr, count);

  25:     for (int i = 0; i < count; i++)

  26:         M(va_arg(arg_ptr, char*));

  27:     va_end(arg_ptr);

  28: }

  29:  

  30: int Deal(int s)

  31: {

  32:     M(b);

  33:     int t = s;

  34:     for (int k = 1; k <= n; k++)

  35:     {

  36:         if (1 & t) b[1][k] = 1;

  37:         else if (a[1][k] == 1) return INF;

  38:         t = t >> 1;

  39:     }

  40:     for (int r = 2; r <= n; r++)

  41:     {

  42:         for (int c = 1; c <= n; c++)

  43:         {    

  44:             int sum = 0;

  45:             if (r > 2) sum += b[r - 2][c];

  46:             if (c > 1) sum += b[r - 1][c - 1];

  47:             if (c < n) sum += b[r - 1][c + 1];

  48:             b[r][c] = sum % 2;

  49:             if (a[r][c] == 1 && b[r][c] == 0) return INF;

  50:         }

  51:     }

  52:     int cnt = 0;

  53:     for (int r = 1; r <= n; r++)

  54:     for (int c = 1; c <= n; c++)

  55:         if (a[r][c] != b[r][c]) cnt += 1;

  56:     return cnt;

  57: }

  58:  

  59: int main()

  60: {

  61:     int cnt = 1;

  62:     scanf("%d", &T);

  63:     while (T--)

  64:     {

  65:         scanf("%d", &n);

  66:         for (int i = 1; i <= n; i++)

  67:             for (int j = 1; j <= n; j++)

  68:                 scanf("%d", &a[i][j]);

  69:         int m = INF;

  70:         for (int s = 0; s < (1 << n); s++)

  71:             m = min(m, Deal(s));

  72:         if (m == INF) m = -1;

  73:         printf("Case %d: %d\n", cnt++, m);

  74:     }

  75:     return 0;

  76: }

UVa 11464 Even Parity 偶数矩阵的更多相关文章

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

    题意:给你一个n*n的01矩阵,让你把这个矩阵中尽量少的0转换成1,使得矩阵每个位置的上下左右四个相邻的数加起来能被2整除,求最少的转换数 首先,n 的规模并不大,最大只有15.但是完全枚举整个矩阵显 ...

  2. UVA.11464 Even Parity (思维题 开关问题)

    UVA.11464 Even Parity (思维题 开关问题) 题目大意 给出一个n*n的01方格,现在要求将其中的一些0转换为1,使得每个方格的上下左右格子的数字和为偶数(如果存在的话),求使得最 ...

  3. 状态压缩+枚举 UVA 11464 Even Parity

    题目传送门 /* 题意:求最少改变多少个0成1,使得每一个元素四周的和为偶数 状态压缩+枚举:枚举第一行的所有可能(1<<n),下一行完全能够由上一行递推出来,b数组保存该位置需要填什么 ...

  4. 【巧妙算法系列】【Uva 11464】 - Even Parity 偶数矩阵

    偶数矩阵(Even Parity, UVa 11464) 给你一个n×n的01矩阵(每个元素非0即1),你的任务是把尽量少的0变成1,使得每个元素的上.下.左.右的元素(如果存在的话)之和均为偶数.比 ...

  5. 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 in ...

  6. UVA 11464 Even Parity(部分枚举 递推)

    Even Parity We have a grid of size N x N. Each cell of the grid initially contains a zero(0) or a on ...

  7. UVa 11464 - Even Parity

    解题报告:题目大意有一个N×N的矩阵,矩阵中的元素只有1或0,如果说对于一个矩阵,它的所有的点的上下左右的点的和是偶数,则称这个矩阵为偶数矩阵,现在给你一个任意的矩阵,要求的是如果要把这个矩阵变成偶数 ...

  8. UVA 11464 - Even Parity(枚举方法)

    D Even Parity Input: Standard Input Output: Standard Output We have a grid of size N x N. Each cell ...

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

    题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...

随机推荐

  1. 全注解的SSH框架

    基于struts2.23 + spring2.5.6 + hibernate3.6.4 + hibernate-generic-dao1.0(除了spring,我整合的都是最新的GA包,hiberna ...

  2. 妙味课堂——HTML+CSS(第三课)

    常见标签我已经在上一篇文章中提及,我们做前端设计时,主要也是用这些标签(最常用的). 然而有一个问题,就是有的标签都有自己的默认样式.试通过如下代码来说明: <!DOCTYPE html> ...

  3. 使用datatable 将测试数据与业务分离

    当基本一致的业务流程, 需要测试繁杂的测试数据时,就可以将测试数据参数化了,同时使用datatable来实现测试数据与业务分离,这个方法在我现在的项目中应用在很多地方,感觉超级方便,现对工作中的应用做 ...

  4. skip list

    概述 Skip list是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的插入和删除的工作是比较简单的.并且是Redis.Leve ...

  5. list, set操作

    def union_list(l1, l2): result = [] if not l1: result.extend(l2) return result if not l2: result.ext ...

  6. mysql 复杂的查询语句,工作中用到的记录下

    1  去重查询 select distinct id from user_info where xxxxxx 2 group by 分组查询中排序 group by本身没有排序功能,这可能是mysql ...

  7. Sublime Text 新建文件可选类型的模版插件: SublimeTmpl

    安装方法: 1.Ctrl+Shift+P打开控制台, 2.输入IP安装插件 3.输入tmpl 回车安装 编辑模版在:SublimeTmpl\templates"文件夹修改 其他情况: htt ...

  8. logback与Log4J的区别

    原文:http://blog.csdn.net/lwzcjd/article/details/5617200 Logback和log4j是非常相似的,如果你对log4j很熟悉,那对logback很快就 ...

  9. 使AJAX调用尽可能利用缓存特性

    优化网站设计(十四):使AJAX调用尽可能利用缓存特性 前言 网站设计的优化是一个很大的话题,有一些通用的原则,也有针对不同开发平台的一些建议.这方面的研究一直没有停止过,我在不同的场合也分享过这样的 ...

  10. NDK(2)使用eclipse + ndk开发过程演示,含CPU架构编译

    环境linux + eclipse + adt + ndk 1,在ide中配置ndk 下载ndk,在eclipse中配置 2,使用ndk编程 2.1 给项目添加ndk 支持 右键 项目名 --> ...