HDU 5755 Gambler Bo 2016多校第三场1004
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5755
题意:给你一个N*M大小的矩阵,在模3域情况下,你可以选矩阵中任意格子使它+2,此时相邻的四个格子会同时+1,让你使用此操作使得整个矩阵每一个地方变为0,输出最小步骤,并且按步骤输出操作的格子。
题解:高斯消元模板题,不过变成了取模。
高斯消元解线性方程:http://jingyan.baidu.com/article/39810a23e40c80b636fda63a.html
那么对于一个模线性方程 a%mod+b%mod+c%mod+....+x%mod=C,如果该方程要求的是a,那么就需要消去其他变量,也就是使得b%mod、c%mod...x%mod变为0。以消去b为例子,关键是要解决假如有另一方程b的系数不为1时,两式相消的情况。那么我们先来考虑一个简单的式子a%mod+b%mod=C,当a、b同时变为原来的两倍也就是2a%mod+2b%mod=D,我们根据式子(a+b)%mod=(a%mod+b%mod)%mod,可以知道D=2C%mod。所以当遇到两个式子同一个变量的系数不相等的时候,只要把两个系数变为相等即可(即求最小公倍数),不过在相乘的时候是怎个式子每一个变量都要乘上相同的倍数,取模结果乘上相同倍数再取模就可以了。详细看代码。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn=905;
int T;
int n,m;
int equ,var;
int x[maxn];
int a[maxn][maxn];
vector<int>v;
inline int Lcm(int x,int y)
{
return x/__gcd(x,y)*y;
}
void guass()
{
int sub_r;
int r,c;
r=c=0;
for(;r<equ&&c<var;r++,c++)
{
sub_r=r;
for(int i=r+1;i<equ;i++)//保证需要求的变量在第i行第i列
if(abs(a[i][c])>abs(a[sub_r][c]))
sub_r=i;
if(sub_r!=r)
for(int i=0;i<var+1;i++)
swap(a[r][i],a[sub_r][i]);
if(a[r][c]==0)
{
r--;
continue;
}
//cout<<a[r][c]<<endl;
for(int i=r+1;i<equ;i++)
{
if(a[i][c])
{
int lcm=Lcm(abs(a[i][c]),abs(a[r][c]));
int tr=lcm/abs(a[r][c]);
int ti=lcm/abs(a[i][c]);
if(a[r][c]*a[i][c]<0)
tr=-tr;
for(int j=c;j<var+1;j++)
{
a[i][j] = ti*a[i][j]-tr*a[r][j];
a[i][j] = (a[i][j]%3+3)%3;
}
}
}
}
for(int i=var-1;i>=0;i--)
{
int tem=a[i][var];
//if(i==var-1)
// cout<<a[i][i]<<" "<<tem<<endl;
for(int j=i+1;j<var;j++)
if(a[i][j])
{
tem-=a[i][j]*x[j];
tem=(tem%3+3)%3;
}
x[i]=tem*a[i][i];
x[i]%=3;
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(x,0,sizeof(x));
memset(a,0,sizeof(a));
scanf("%d%d",&n,&m);
equ=var=m*n;
for(int i=0;i<var;i++)
{
a[i][i]=2;
int tr=i/m,tc=i%m;
if(tr>0)
a[i][i-m]=1;
if(tr<n-1)
a[i][i+m]=1;
if(tc>0)
a[i][i-1]=1;
if(tc<m-1)
a[i][i+1]=1;
}
int b;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&b);
a[i*m+j][var]=(3-b)%3;
}
}
guass();
v.clear();
for(int i=0;i<var;i++)
{
//cout<<x[i]<<endl;
while(x[i]--)
v.push_back(i);
}
printf("%d\n",v.size());
for(int i=0;i<v.size();i++)
{
int tx=v[i]/m;
int ty=v[i]%m;
printf("%d %d\n",tx+1,ty+1);
}
}
return 0;
}