题目链接:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2459
题目大意:
有一个N×N的矩阵,矩阵中的元素只有1或0,如果说对于一个矩阵,它的所有的点的上下左右的点的和是偶数,则称这个矩阵为偶数矩阵,现在给你一个任意的矩阵,要求的是如果要把这个矩阵变成偶数矩阵的话,最少需要将多少个点由1变成0,若不存在话,输出-1.(N<=15)
题目分析:
这题如果枚举每个点的情况的话,虽然N最大只有15,但这样枚举的计算量依然非常大。但是我们可以发现,如果知道第一行的每一个点是什么样的,完全可以计算出下面的N-1行的每一个点。这样我们只要枚举第一行的每一个点的情况,这样的话时间复杂度就降为2^15,很明显快多了。
代码:
#include <iostream>
using namespace std;
int map[20][20],tt[20][20],mi,n,k;
int qiuhe(int ii,int jj) //求第(ii,jj)上下左右之和
{
int s=0;
if(ii-1>=0) s+=tt[ii-1][jj];
if(jj-1>=0) s+=tt[ii][jj-1];
if(jj+1<n) s+=tt[ii][jj+1];
return s;
}
int work(int kk) //成功返回修改次数,失败返回-1
{ int i,j;
for(i=1;i<n;i++)//从第一行开始递推
for(j=0;j<n;j++)
{
int s=qiuhe(i-1,j);
if(s%2==0) //he为偶,需要0
{
if(map[i][j]==1) return -1;
else tt[i][j]=0;
}
else //he为奇,需要1
{
if(map[i][j]==1) tt[i][j]=1;
else {tt[i][j]=1;kk++;}
}
}
for(j=0;j<n;j++) //判断最后一行是否满足条件
if(qiuhe(n-1,j)%2==1) return -1;
return kk;
}
void out()
{
int i,j;
cout<<"**********"<<endl;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(j!=n-1) cout<<tt[i][j]<<" ";
else cout<<tt[i][j]<<endl;
}
cout<<"**********"<<endl;
}
void meiju(int ii) //枚举第1行的n个元素
{
if(ii==n)
{ //cout<<"k:"<<k<<endl;
int s=work(k);
//if(s>=0) {cout<<"s:"<<s<<endl; out();}
if(s>=0&&mi>s) mi=s;
}
else
{
if(map[0][ii]==0)
{
tt[0][ii]=1;
k++;
meiju(ii+1);
tt[0][ii]=0;
k--;
meiju(ii+1);
}
else meiju(ii+1);
}
}
int main()
{
int t,i,j,Case=1;
cin>>t;
while(t--)
{
mi=999999; k=0;
cin>>n;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
cin>>map[i][j],tt[i][j]=map[i][j];
meiju(0);
cout<<"Case "<<Case++<<": ";
if(mi!=999999)cout<<mi<<endl;
else cout<<-1<<endl;
}
return 0;
}