http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=24665
题意:
给你一个 n * n 的 01 矩阵,现在你的任务是将这个矩阵中尽量少的 0 转化为 1 ,使得每个数的上下左右四个相邻的数(如果存在)加起来是偶数。求最少的转化个数。n<=15
n规模很小...直接暴力枚举整个矩阵2^(15*15)显然不科学....
可以发现只要第一行确定了,就能推出第二行...再从第二行推出第三行..
也就是只要暴力枚举第1行就好了 复杂度O(2^n) 每种情况对应要枚举一个矩阵,所以总复杂度O(2^n * n*n)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
int ori[16][16];
int tm[16][16];
const int inf=2147483647;
int n;
void copy_( )
{
for (int i=2;i<=n;i++)
for (int j=1;j<=n;j++)
tm[i][j]=ori[i][j];
}
int ok(int i,int j)
{
int sum=0;
if (i+1<=n) sum+= tm[i+1][j];
if (i-1>=1) sum+= tm[i-1][j];
if (j+1<=n) sum+= tm[i][j+1];
if (j-1>=1) sum+= tm[i][j-1];
if (sum%2) return 0;
else
return 1;
}
int min(int a,int b)
{return a<b?a:b;}
int main()
{
int t;
cin>>t;
int cnt=1;
while(t--)
{
int minn=inf;
int i,j,k;
scanf("%d",&n);
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
scanf("%d",&ori[i][j]);
}
int cun=pow(2.0,n);
for (i=0;i<cun;i++)
{
int ans=0;
copy_();//copy ori[] to tm[]
int tmp=i;
int cun=0;
for (j=1;j<=n;j++)
{
if (ori[1][j]==1) continue; //only transfrom 0 to 1;
tm[1][j]=tmp&1;
if (ori[1][j]==0&&tm[1][j]==1) cun++; //count the num of changed “1” from “0”
tmp>>=1;
}
for (j=2;j<=n;j++)
{
for (k=1;k<=n;k++)
{
if (!ok(j-1,k)) //if (the sum%2!=0)
{
if (tm[j][k]==1) //cannot change
{
ans=inf;
break;
}
ans++; //can change
tm[j][k]=!tm[j][k];
}
}
if (ans==inf) break;
}
if (ans==inf) continue;
minn=min(minn,ans+cun);
}
if (minn==inf)
minn=-1;
printf("Case %d: %d\n",cnt++,minn);
}
return 0;
}