偶數矩陣 Even Parity,UVa 11464

題目描述 Description

給你一個n*n的01矩陣(每一個元素非0即1),你的任務是把儘可能少的0變成1,使得每一個元素的上、下、左、右的元素(若是存在的話)之和均爲偶數。如圖所示的矩陣至少要把3個0變成1,最終如圖所示,才能保證其爲偶數矩陣。c++

 輸入輸出格式 Input/output
輸入格式:
輸入的第一行爲數據組數T(T<30)。每組數據的第一行爲正整數n(1 < n < 15);接下來的n行每行包含n個非0即1的整數,相鄰整數間用一個空格隔開。
輸出格式:
對於每組數據,輸出被改變的元素的最小個數。若是無解,應輸出-1。
 輸入輸出樣例 Sample input/output
樣例測試點#1
輸入樣例:

0 0 0測試

1 0 0spa

0 0 0code

輸出樣例:
3
 
思路:這道題很經典,經典的枚舉也有DP的意味在裏面,這裏我把書上的思路詳細化。
書上談到:拋棄枚舉每一個數字的方法,這樣很大,大概2 255這麼多的狀況,很大,難以接受,能夠考慮枚舉第一行,這樣有2 15種可能,是可行的,根據第一行算出第二行,以此類推到第n行,時間複雜度降爲O(2 n×n 2)
點石成金罷了,下面來講說如何具體的作到:
將樣例的第一行:
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\n",T,ans);
67         T--;
68     } 
69     return 0;
70 }
相關文章
相關標籤/搜索