题意: 一个nxm的矩阵,每个方格会有一个权值,我们假使点击方格(x,y),那么v[x][y]+2, v[x+1][y]+1, v[x-1][y]+1, v[x][y+1]+1, v[x][y-1]+1,即自己的位置+2,上下左右四个位置+1,各个方格的值mod3, 问题是求,我们选择怎样的一个方案,使左右的方格的权值都变为0.
我们可以根据各个方格的,来列出n*m的式子,例:
v[x][y]+2*s[x][y]+1*s[x-1][y]+1*s[x+1][y]+1*s[x][y-1]+1*s[x][y+1]+0*s[]....=0 (v代表权值 , s代表对应位置的点击次数)
举例: 当前有 2 1 2 这样一个矩阵 ,我们可以列出6个式子 : (1)v[0][0]+2*s[0][0]+1*s[1][0]+1*s[0][1]+0*s[]....=0
0 2 0
然后接下来我们套用高斯消元模板 求解:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#define F first
#define S second
#define mp make_pair
using namespace std;
const int maxn = 910;
int a[maxn][maxn];
int x[maxn];
inline int gcd(int a,int b)
{
int t ;
while(b!=0)
{
t=b;
b=a%b;
a=t;
}
return a;
}
inline int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
long long inv(long long a,long long m)
{
if(a==1) return 1;
return inv(m%a,m)*(m-m/a)%m;
}
void Guass(int n,int m)
{
int i,j,r;
int max_r;
int c;
int ta,tb ;
int LCM;
int temp;
for(int i=0; i<=m; i++)
{
x[i]=0;
}
for(r=0, c=0 ; r<n && c<m ; r++, c++)
{
max_r=r;
for(int i=r+1; i<n; i++)
{
if(abs(a[i][c])>abs(a[max_r][c]))
max_r=i;
}
if(max_r!=r)
{
for(j=c; j<m+1; j++)
{
swap(a[r][j],a[max_r][j]);
}
}
if(a[r][c]==0)
{
r--;
continue;
}
for(i=r+1; i<n; i++)
{
if(a[i][c]!=0)
{
LCM=lcm(abs(a[i][c]),abs(a[r][c]));
ta = LCM/abs(a[i][c]);
tb = LCM/abs(a[r][c]);
if(a[i][c]*a[r][c]<0) tb=-tb;
for(j=c; j<m+1; j++)
{
a[i][j]=a[i][j]*ta-a[r][j]*tb;//小心爆longlong的情况
a[i][j]=(a[i][j]%3+3)%3;
}
}
}
}
for (i=m-1; i>=0; i--)
{
temp=a[i][m];
if(a[i][i]==0)
{
// x[i]=0;
continue;
}
for(j=i+1; j<m; j++)
{
if(a[i][j]!=0) temp-=a[i][j]*x[j];
}
temp=(temp%3+3)%3;
x[i]=temp*inv(a[i][i],3);
x[i]=(x[i]%3+3)%3;
}
}
int main()
{
int T,n,m,as;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(i>0) a[i*m+j][(i-1)*m+j]=1;
if(i<n-1) a[i*m+j][(i+1)*m+j]=1;
if(j>0) a[i*m+j][i*m+j-1]=1;
if(j<m-1) a[i*m+j][i*m+j+1]=1;
a[i*m+j][i*m+j]=2;
scanf("%d",&as);
a[i*m+j][n*m]=((3-as)%3)%3;
}
}
Guass(n*m,n*m);
int sum=0;
for(int i=0; i<n*m; i++)
{
if(x[i]) sum+=x[i];
}
printf("%d\n",sum);
for(int i=0; i<n*m; i++)
{
if(x[i])
while(x[i]--)
printf("%d %d\n",i/m+1,i%m+1);
}
}
}
附上高斯消元模板:
http://www.cnblogs.com/kuangbin/archive/2012/09/01/2667044.html