• 偶数矩阵 Even Parity,UVa 11464


    题目描述 Description

    给你一个n*n的01矩阵(每个元素非0即1),你的任务是把尽量少的0变成1,使得每个元素的上、下、左、右的元素(如果存在的话)之和均为偶数。如图所示的矩阵至少要把3个0变成1,最终如图所示,才能保证其为偶数矩阵。

     输入输出格式 Input/output
    输入格式:
    输入的第一行为数据组数T(T<30)。每组数据的第一行为正整数n(1 < n < 15);接下来的n行每行包含n个非0即1的整数,相邻整数间用一个空格隔开。
    输出格式:
    对于每组数据,输出被改变的元素的最小个数。如果无解,应输出-1。
     输入输出样例 Sample input/output
    样例测试点#1
    输入样例:

    0 0 0

    1 0 0

    0 0 0

    输出样例:
    3
     
    思路:这道题很经典,经典的枚举也有DP的意味在里面,这里我把书上的思路详细化。
    书上谈到:抛弃枚举每个数字的方法,这样很大,大概2255这么多的情况,很大,难以接受,可以考虑枚举第一行,这样有215种可能,是可行的,根据第一行算出第二行,以此类推到第n行,时间复杂度降为O(2n×n2)
    点石成金罢了,下面来说说如何具体的做到:
    将样例的第一行:
    0 0 0
    可以通过枚举变成
    0 1 0
    这样第一行就确定下来了,这时候考虑第二行:
    0 1 0
    α
    考虑一下第一行第一列的0,它的上下左右加和=α+1,那么这时候要保证是偶数,即(α+1)%2==0,所以α=1,这时候看看这个α可不可以由原矩阵A的这个位置的数变化而来(即0→1),合法,此时记上1。
    0 1 0
    1 α
    同样计算第一行第二列,(0+α+0)%2==0,α=0,比较原矩阵,合法,记上0。
    0 1 0
    1 0 α
    同上,合法变换矩阵为:
    0 1 0
    1 0 1
    最终执行完:
    0 1 0
    1 0 1
    0 1 0
     
    大致的思路就是这样,要注意的是一些细节之处,比如位运算简化,这样可以使代码简洁很多且运算方便
     
    代码如下(书上copy下来且加了点注释的):
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <math.h>
     5 const int MAXN=20;
     6 const int INF=100000;
     7 int A[MAXN][MAXN],B[MAXN][MAXN];
     8 int n;
     9 int min(int a,int b)
    10 {
    11     return a>b?b:a;
    12 }
    13 int check(int s)
    14 {
    15     memset(B,0,sizeof(int));
    16     for(int c=0;c<n;c++)//枚举第一行 
    17     {
    18         if(s&(1<<c)) B[0][c]=1;
    19         else if(A[0][c]==1) return INF;//不能把1变成0,直接返回 
    20     }
    21     for(int r=1;r<n;r++)//从第二行开始依次筛查 
    22     {
    23         for(int c=0;c<n;c++)
    24         {
    25             int sum=0;//表示上左右三个元素的和 
    26             if(r>1) sum+=B[r-2][c];
    27             if(c>0) sum+=B[r-1][c-1];
    28             if(c<n-1) sum+=B[r-1][c+1];
    29             B[r][c]=sum%2;
    30             if(A[r][c]==1&&B[r][c]==0) return INF;//违法,不能把1变为0 
    31         }
    32     }
    33     int cnt=0;
    34     for(int r=0;r<n;r++)
    35     {
    36         for(int c=0;c<n;c++)
    37         {
    38             if(A[r][c]!=B[r][c]) cnt++;
    39         }
    40     }
    41     return cnt;
    42 } 
    43 int main()
    44 {
    45     int r,c;//行、列
    46     int i,j;
    47     int T;
    48     int ans=INF;//初始化为最大值 
    49     scanf("%d",&T);
    50     while(T)
    51     {
    52         ans=INF;
    53         scanf("%d",&n);
    54         for(i=0;i<n;i++)
    55         {
    56             for(j=0;j<n;j++)
    57             {
    58                 scanf("%d",&A[i][j]);
    59             }
    60         }
    61         for(int s=0;s<(1<<n);s++)//1<<n等于2^n,不用pow,比较方便 
    62         {
    63             ans=min(ans,check(s));//不断更新最小ans 
    64         }
    65         if(ans==INF) ans=-1;//没找到答案 
    66         printf("%d %d
    ",T,ans);
    67         T--;
    68     } 
    69     return 0;
    70 }
  • 相关阅读:
    计算机考研真题 浮点数加法
    计算机考研复试真题 整数奇偶排序
    计算机考研复试 A+B
    计算机考研复试真题 整数拆分
    计算机考研复试真题 众数
    1121 Damn Single (25 分)
    1112 Stucked Keyboard (20 分)
    1117 Eddington Number (25 分)
    1005 继续(3n+1)猜想 (25 分)
    1047 编程团体赛 (20 分)
  • 原文地址:https://www.cnblogs.com/geek-007/p/11669643.html
Copyright © 2020-2023  润新知