even parity

转自http://www.acmerblog.com/uva-11464-even-parity-4653.html

这道题的算法实现态变态了,奇妙的技巧,至少我是这样认为的。我想了很久也不会,书上代码看不懂,这篇讲的比较清晰。

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).

Suppose we have a grid of size 4 x 4:

1 0 1 0

The parity of each cell would be

1 3 1 2
1 1 1 1 2 3 3 1
0 1 0 0 2 1 2 1
0 0 0 0 0 1 0 0

 

For this problem, you have to change some of the 0s to 1s so that the parity of every cell becomes even. We are interested in the minimum number of transformations of 0 to 1 that is needed to achieve the desired requirement.

Input

The first line of input is an integer T (T<30) that indicates the number of test cases. Each case starts with a positive integer N(1≤N≤15). Each of the next N lines contain N integers (0/1) each. The integers are separated by a single space character.

Output

For each case, output the case number followed by the minimum number of transformations required. If it’s impossible to achieve the desired result, then output -1 instead.

Sample Input      

01 3
02 3
03 0 0 0
04 0 0 0
05 0 0 0
06 3
07 0 0 0
08 1 0 0
09 0 0 0
10 3
11 1 1 1
12 1 1 1
13 0 0 0

Output for Sample Input

1 Case 1: 0
2 Case 2: 3
3 Case 3: -1

解题报告:题目大意有一个N×N的矩阵,矩阵中的元素只有1或0,如果说对于一个矩阵,它的所有的点的上下左右的点的和是偶数,则称这个矩阵为偶数矩阵,现在给你一个任意的矩阵,要求的是如果要把这个矩阵变成偶数矩阵的话,最少需要将多少个点由1变成0,若不存在话,输出-1.(N<=15)

分析时间复杂度。 由题目可知矩阵的最大的行数为15,那么我们最容易想到就是去枚举每一个位置的数,那么矩阵的最多的元素为255,那么255个元素的状态为2^255,很明显这个是不可能实现的。
那么我们相到第一行的状态最多为2^15的,那么我们知道如果一个矩阵满足题目要求的话就是每一个元素的周围四个元素之和为偶数,那么我们就可以通过第一行求出第二行,利用第二行求出第三行…
那么我们只要去枚举第一行的2进制的每一个值,然后判断即可。

01 #include<cstring> 
02 #include<cstdio> 
03 #include<iostream> 
04 #include<algorithm> 
05 using namespace std; 
06  
07 const int INF = 1<<30; 
08 const int MAXN = 20; 
09 int m[MAXN][MAXN]; 
10  
11 int solve(int n , int s){ 
12     int tmp[MAXN][MAXN]; 
13     memset(tmp , 0 , sizeof(tmp)); 
14     for(int i = 0 ; i < n ; i++){ 
15        if(s & (1<<i))//说明这一位是1 
16           tmp[0][i] = 1; 
17        else if(m[0][i] == 1)//这里得到的是0,但是实际上1不可能存在 
18           return INF; 
19     
20     //求出tmp数组 
21     for(int i = 1 ; i < n ; i++){ 
22        for(int j = 0 ; j < n ; j++){ 
23           int sum = 0;//通过前一行求出下一行 
24           if(i > 1)//加上 
25              sum += tmp[i-2][j]; 
26           if(j > 0)//加左 
27              sum += tmp[i-1][j-1]; 
28           if(j < n-1) 
29              sum += tmp[i-1][j+1]; 
30           //通过sum求出第tmp[i][j]; 
31           if(sum%2)//如果sum为奇数 
32              tmp[i][j] = 1; 
33           if(tmp[i][j] == 0 && m[i][j] == 1)//如果现在为0但是原先为1这种情况是不可能的 
34              return INF; 
35        
36     
37     //求出这次的变换的次数 
38     int cnt = 0; 
39     for(int i = 0 ; i < n ; i++) 
40        for(int j = 0 ; j < n ; j++) 
41           if(m[i][j] != tmp[i][j]) 
42              cnt++; 
43     return cnt; 
44
45  
46 int main(){  
47     int Case , n , cnt = 1; 
48     scanf("%d" , &Case); 
49     while(Case--){ 
50         scanf("%d" , &n); 
51         for(int i = 0 ; i < n ; i++) 
52            for(int j = 0 ; j < n ; j++) 
53               scanf("%d" , &m[i][j]); 
54         int ans = INF; 
55         for(int i = 0 ; i < (1<<n) ; i++)//枚举第一行的状态 
56            ans = min(ans , solve(n , i));//求最小的ans 
57         printf("Case %d: %d\n" , cnt++ , ans == INF ? -1 : ans); 
58     
59     return 0; 
60 }
  

  • zhouleyu.com

    能不能说一下tmp数组和solve都是干嘛的?

  • 我叫空格_
    1. 我叫空格_
      我叫空格_ 5月11日
      1楼
      能不能说一下tmp数组和solve都是干嘛的?       
    2. dragon
      dragon 5月11日
      2楼
      遍历了所有的情况(2^n),tmp数组就是由当前遍历的状态s推算出的       

    懂了,谢谢啦

  • dragon
    dragon
    1. 我叫空格_
      我叫空格_ 5月11日
      1楼
      能不能说一下tmp数组和solve都是干嘛的?       

    遍历了所有的情况(2^n),tmp数组就是由当前遍历的状态s推算出的

  • 我叫空格_

    能不能说一下tmp数组和solve都是干嘛的?

 
首页 >  ACM题库 >  UVA > Uva-11464-Even Parity[模拟]
201402-27

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).

Suppose we have a grid of size 4 x 4:

1010

The parity of each cell would be

1312
11112331
01002121
00000100

 

For this problem, you have to change some of the 0s to 1s so that the parity of every cell becomes even. We are interested in the minimum number of transformations of 0 to 1 that is needed to achieve the desired requirement.

Input

The first line of input is an integer T (T<30) that indicates the number of test cases. Each case starts with a positive integer N(1≤N≤15). Each of the next N lines contain N integers (0/1) each. The integers are separated by a single space character.

Output

For each case, output the case number followed by the minimum number of transformations required. If it’s impossible to achieve the desired result, then output -1 instead.

Sample Input      

013
023
030 0 0
040 0 0
050 0 0
063
070 0 0
081 0 0
090 0 0
103
111 1 1
121 1 1
130 0 0

Output for Sample Input

1Case 1: 0
2Case 2: 3
3Case 3: -1

解题报告:题目大意有一个N×N的矩阵,矩阵中的元素只有1或0,如果说对于一个矩阵,它的所有的点的上下左右的点的和是偶数,则称这个矩阵为偶数矩阵,现在给你一个任意的矩阵,要求的是如果要把这个矩阵变成偶数矩阵的话,最少需要将多少个点由1变成0,若不存在话,输出-1.(N<=15)

分析时间复杂度。 由题目可知矩阵的最大的行数为15,那么我们最容易想到就是去枚举每一个位置的数,那么矩阵的最多的元素为255,那么255个元素的状态为2^255,很明显这个是不可能实现的。那么我们相到第一行的状态最多为2^15的,那么我们知道如果一个矩阵满足题目要求的话就是每一个元素的周围四个元素之和为偶数,那么我们就可以通过第一行求出第二行,利用第二行求出第三行…那么我们只要去枚举第一行的2进制的每一个值,然后判断即可。

01#include<cstring> 
02#include<cstdio> 
03#include<iostream> 
04#include<algorithm> 
05using namespace std; 
06 
07const int INF = 1<<30; 
08const int MAXN = 20; 
09int m[MAXN][MAXN]; 
10 
11int solve(int n , int s){ 
12    int tmp[MAXN][MAXN]; 
13    memset(tmp , 0 , sizeof(tmp)); 
14    for(int i = 0 ; i < n ; i++){ 
15       if(s & (1<<i))//说明这一位是1 
16          tmp[0][i] = 1; 
17       else if(m[0][i] == 1)//这里得到的是0,但是实际上1不可能存在 
18          return INF; 
19    
20    //求出tmp数组 
21    for(int i = 1 ; i < n ; i++){ 
22       for(int j = 0 ; j < n ; j++){ 
23          int sum = 0;//通过前一行求出下一行 
24          if(i > 1)//加上 
25             sum += tmp[i-2][j]; 
26          if(j > 0)//加左 
27             sum += tmp[i-1][j-1]; 
28          if(j < n-1) 
29             sum += tmp[i-1][j+1]; 
30          //通过sum求出第tmp[i][j]; 
31          if(sum%2)//如果sum为奇数 
32             tmp[i][j] = 1; 
33          if(tmp[i][j] == 0 && m[i][j] == 1)//如果现在为0但是原先为1这种情况是不可能的 
34             return INF; 
35       
36    
37    //求出这次的变换的次数 
38    int cnt = 0; 
39    for(int i = 0 ; i < n ; i++) 
40       for(int j = 0 ; j < n ; j++) 
41          if(m[i][j] != tmp[i][j]) 
42             cnt++; 
43    return cnt; 
44
45 
46int main(){  
47    int Case , n , cnt = 1; 
48    scanf("%d" , &Case); 
49    while(Case--){ 
50        scanf("%d" , &n); 
51        for(int i = 0 ; i < n ; i++) 
52           for(int j = 0 ; j < n ; j++) 
53              scanf("%d" , &m[i][j]); 
54        int ans = INF; 
55        for(int i = 0 ; i < (1<<n) ; i++)//枚举第一行的状态 
56           ans = min(ans , solve(n , i));//求最小的ans 
57        printf("Case %d: %d\n" , cnt++ , ans == INF ? -1 : ans); 
58    
59    return 0; 
60}
  
  • zhouleyu.com

    能不能说一下tmp数组和solve都是干嘛的?

  • 我叫空格_
    1. 我叫空格_
      我叫空格_ 5月11日
      1楼
      能不能说一下tmp数组和solve都是干嘛的?       
    2. dragon
      dragon 5月11日
      2楼
      遍历了所有的情况(2^n),tmp数组就是由当前遍历的状态s推算出的       

    懂了,谢谢啦

  • dragon
    dragon
    1. 我叫空格_
      我叫空格_ 5月11日
      1楼
      能不能说一下tmp数组和solve都是干嘛的?       

    遍历了所有的情况(2^n),tmp数组就是由当前遍历的状态s推算出的

  • 我叫空格_

    能不能说一下tmp数组和solve都是干嘛的?

 
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值