UVA 11464-Even Parity(偶數矩陣-開關問題)

kewlgrl發表於2016-10-19

11464 - Even Parity

Time limit: 3.000 seconds

We have a grid of size N × N. Each cell of the grid initially contains a zero(0) or a one(1). The parityof 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 × 4:


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

Input

The first line of input is an integer T (T < 30) that indicates the number of test cases. Each case startswith a positive integer N (1 ≤ N ≤ 15). Each of the next N lines contain N integers (0/1) each. Theintegers 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

3
3
0 0 0
0 0 0
0 0 0
3
0 0 0
1 0 0
0 0 0
3
1 1 1
1 1 1
0 0 0

Sample Output

Case 1: 0

Case 2: 3

Case 3: -1

題目意思:

有一個N*N的01矩陣,你的任務是把儘量少的0變成1,使得每個元素的上下左右的元素(若存在)均為偶數。

解題思路:

Note:0可以變成1,但是1不能變成0

N最大是15,我們只需要列舉第一行,每個數只能為0/1,所以最多2^15個,剩下的每一行都可以根據第一行來確定。

求解過程中用一個新的矩陣儲存我們找到的解,與原矩陣相比較,計算出改變的元素個數。

列舉過程中:

①狀態壓縮

if(s & (1<<i)) m[0][i]=1;//判斷該位是否為1
因為數最大範圍是000~111共15種,所以可以分別對應列舉第一行元素值的所有情況。

按位與&運算(只有全1才為1)判斷該位是否為1,如果是1,則新矩陣該位置1;如果原來的矩陣中該位為1,則無法求解,函式直接返回返回無解;

1不能變成0

 if(f[i][j]==1&&m[i][j]==0) return INF;//別忘了這句,1不能轉換成0
注意特判這種無法轉換的情況,無法繼續求解,函式直接返回返回無解。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <bitset>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 16
int m[maxn][maxn],f[maxn][maxn];
int n;
int valid(int s)
{
    memset(m,0,sizeof(m));
    int cnt=0;
    for(int i=0; i<n; ++i)
    {
        if(s & (1<<i)) m[0][i]=1;
        else if(f[0][i]==1) return INF;
    }
    for(int i=1; i<n; ++i)
        for(int j=0; j<n; ++j)
        {
            int sum=0;
            if(i>1)//上
                sum+=m[i-2][j];
            if(j>0)//左
                sum+=m[i-1][j-1];
            if(j+1<n)//右
                sum+=m[i-1][j+1];
            m[i][j]=sum%2;
            if(f[i][j]==1&&m[i][j]==0) return INF;//別忘了這句,1不能轉換成0
        }
    for(int i=0; i<n; ++i)
        for(int j=0; j<n; ++j)
            if(m[i][j]!=f[i][j]) ++cnt;
    return cnt;
}
int main()
{
    int t,ca=0;
    scanf("%d",&t);
    while(t--)
    {
        int ans=INF;
        scanf("%d",&n);
        for(int i=0; i<n; ++i)
            for(int j=0; j<n; ++j)
                scanf("%d",&f[i][j]);
        for(int i=0; i<(1<<n); ++i)
            ans=min(ans,valid(i));
        if(ans==INF) ans=-1;
        printf("Case %d: %d\n",++ca,ans);
    }
    return 0;
}
/*
3
3
0 0 0
0 0 0
0 0 0
3
0 0 0
1 0 0
0 0 0
3
1 1 1
1 1 1
0 0 0

*/


相關文章