题意:
一个0/1矩阵,表示开关,0关,1开,按(i,j)这个开关后则跟他曼哈顿距离为d的开关改变状态.
问能否将改状态变为全0.
题解:
首先逆向思维,题目要求等价于将全0变为所求矩阵.
然后对于每一个开关,要么按一次,要么不按,按两次以上等价于按了%2次,设未知数x(i,j)表示按1次或0次.
则可以列n*m个方程:
x(i,j)+sigma(x(ii,jj))=a[i][j] (a[i][j]为给定0/1矩阵里的值,x(ii,jj)跟(i,j)曼哈顿距离为d的开关)
代码:
/*
* File: main.cpp
* Author: swordholy
*
* Created on 2011年4月6日, 下午1:10
*/
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
#define MAXN 650
struct Matrix
{
int n,m;
int e[MAXN][MAXN];
void set(int mm)
{
n=0;m=mm;
memset(e,0,sizeof(e));
}
void AddEq(int *a)
{
n++;
int i;
for(i=1;i<=m;i++)
e[n][i]=a[i];
}
void swap(int u,int v)
{
int i,temp;
for(i=1;i<=m;i++)
{
temp=e[u][i];
e[u][i]=e[v][i];
e[v][i]=temp;
}
}
bool gauss()
{
int i,j,k,maxk,kk;
for(i=1,j=1;i<=n&&j<=m-1;i++,j++)
{
maxk=i;
for(k=i+1;k<=n;k++)
if (e[i][j]<e[k][j]) maxk=k;
swap(i,maxk);
if (e[i][j]==0) {i--;continue;}
for(k=i+1;k<=n;k++)
{
if (e[k][j]==0) continue;
for(kk=1;kk<=m;kk++)
e[k][kk]^=e[i][kk];
}
}
for(k=i;k<=n;k++)
if (e[k][m]!=0) return 0;
return 1;
}
};
Matrix mt;
int a[MAXN][MAXN];
int n,m;
int idx(int i,int j)
{
return (i-1)*m+j;
}
int t[MAXN];
int main(int argc, char** argv)
{
int i,j,k,d;
while(scanf("%d%d%d",&m,&n,&d)!=EOF)
{
if ( (n==0)&&(m==0)&&(d==0) ) break;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
mt.set(n*m+1);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
memset(t,0,sizeof(t));
t[idx(i,j)]=1;
for(int ii=1;ii<=n;ii++)
for(int jj=1;jj<=m;jj++)
if (abs(i-ii)+abs(j-jj)==d)
{
t[idx(ii,jj)]=1;
}
t[n*m+1]=a[i][j];
mt.AddEq(t);
}
printf("%d/n",mt.gauss());
}
return 0;
}