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;
}

posted on 2016-08-22 19:11  57老帅了  阅读(167)  评论(0编辑  收藏  举报

导航