PS. 看了大神的题解,发现确实可以用m个未知数的高斯消元做。因为确定了第一行的情况,之后所有行的情况都可以根据第一行推。 这样复杂度直接变成O(m*m*m)

知道了是高斯消元后,其实只要稍加处理,就可以解决带模的情况。

1 是在进行矩阵行变化的时候,取模。

2 最后的除法用逆元。(因为a[i][i]必定非0 且小于模数)

然后对于无穷多解的情况,只需要将那些列全为0的未知数定义一个固定值。(这里设的是0)其余操作不变。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string> #define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x) ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b) #define ll long long
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 1010
using namespace std;
//freopen("din.txt","r",stdin); int a[N][N],X[N];//分别记录增广矩阵和解集
int free_x[N];//记录自由变量
int equ,var;//分别表示方程组的个数和变量的个数 int GCD(int x,int y){
if (y == ) return x;
return GCD(y,x%y);
}
int LCM(int x,int y){
return x/GCD(x,y)*y;
}
void Debug(void)
{
int i, j;
for (i = ; i < equ; i++)
{
for (j = ; j < var + ; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,
//但无整数解,-1表无整数解,-1表示无解,0表示唯一解,大于0表示无穷解,
//并返回自由变元的个数) //ax + by = gcd(a,b)
//传入固定值a,b.放回 d=gcd(a,b), x , y
void extendgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(b==){d=a;x=;y=;return;}
extendgcd(b,a%b,d,y,x);
y-=x*(a/b);
} //Ax=1(mod M),gcd(A,M)==1
//输入:10^18>=A,M>=1
//输出:返回x的范围是[1,M-1]
ll GetNi(ll A,ll MM)
{
ll rex=,rey=;
ll td=;
extendgcd(A,MM,td,rex,rey);
return (rex%MM+MM)%MM;
} int Guass(){
int i,j,k,col;
CL(X,); CL(free_x,); for (k = ,col = ; k < equ && col < var; k++, col++){
int max_r = k;
for (i = k + ; i < equ; ++i){
if (iabs(a[i][col]) > iabs(a[max_r][col])) max_r = i;
}
if (max_r != k){
for (i = k; i < var + ; ++i) swap(a[k][i],a[max_r][i]);
}
if (a[k][col] == ){
//可以随意定义的变量
X[col] = ;//强制赋值为0
free_x[col] = ;
k--;
//cout<<k<<endl;
continue;
}
for (i = k + ; i < equ; ++i){
if (a[i][col] != ){
int lcm = LCM(a[k][col],a[i][col]);
int ta = lcm/iabs(a[i][col]); int tb = lcm/iabs(a[k][col]);
if (a[i][col]*a[k][col] < ) tb = -tb;
for (j = col; j < var + ; ++j){
a[i][j] = ((ta*a[i][j] - tb*a[k][j])%+)%;
}
}
}
}
//Debug();
// 1. 无解的情况:
for (i = k; i < equ; ++i){
if (a[i][col] != ) return -;
}
// 2. 无穷解的情况:
if (k < var){ int num = ,freeidx=;
for (i = k - ; i >= ; --i){
num = ;
int tmp = a[i][var];
for (j = ; j < var; ++j){
if (a[i][j] != && free_x[j]){
num++;
freeidx = j;
}
}
if (num > ) continue;
tmp = a[i][var];
for (j = ; j < var; ++j){
if (a[i][j] && j != freeidx) tmp -= a[i][j]*X[j];
}
//这里也要 int k2 = (tmp%+)%;
int k1 = (a[i][freeidx]%+)%;
if(k1!=)
{
X[freeidx] = k2*(int)GetNi(k1, );
}
else
{
X[freeidx] = ;
//printf("X[%d]为任意?\n",i);
} //X[freeidx] = tmp/a[i][freeidx];
free_x[freeidx] = ;
}
return var - k;
}
// 3. 唯一解的情况:
for (i = k - ; i >= ; --i){
int tmp = a[i][var];
for (j = i + ; j < var; ++j){
tmp -= a[i][j]*X[j];
}
//强行搞一发
int k2 = (tmp%+)%;
int k1 = (a[i][i]%+)%;
if(k1!=)
{
X[i] = k2*(int)GetNi(k1, );
}
else
{
X[i] = ;
//printf("X[%d]为任意?\n",i);
}
//X[i] = tmp/a[i][i];//不整除?
}
return ;
} int g[][]; int getid(int i,int j,int n,int m)
{
return (i-)*m + (j-);
}
int up[]={,-,,};
int rl[]={,,,-}; int main(){
//freopen("din.txt","r",stdin);
int i,j; int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
for(j=;j<=m;j++)
scanf("%d",&g[i][j]);
equ = n*m;
var = n*m; memset(a,,sizeof(a)); int id = ;
for(i=;i<=n;i++)
for(j=;j<=m;j++)
{
for(int k=;k<;k++)
{
int ti = i+up[k];
int tj = j+rl[k];
if( ti>=&&ti<=n && tj>=&&tj<=m )
{
int tid = getid(ti, tj, n, m);
a[id][tid] = ;
}
} a[id][id] = ;
a[id][n*m] = (-g[i][j])%;
id++;
}
CL(X,);
CL(free_x,);
//for (i = 0; i < equ; ++i)
//for (j = 0; j < var + 1; ++j) scanf("%d",&a[i][j]);
//Debug(); int free_num = Guass(); if (free_num == -) printf("无解!\n");
else if (free_num == -) printf("无整数解\n");
else {
// else if (free_num > 0){ //printf("无穷多解! 自由变元个数为%d\n", free_num);
//我懂了,我需要确定free_num个数
// for (i = 0; i < var; ++i){
// if (free_x[i]) printf("X%d 是不确定的\n",i + 1);
// else printf("X%d %d\n",i + 1,X[i]);
// } // }
// else{
//我觉得可以!
int ans = ;
for (i = ; i < var; ++i){
if(X[i]% != ) ans += (X[i]%+)%;
//printf("X%d %d\n",i + 1,X[i]);
}
printf("%d\n",ans);
for(i=;i<var;i++)
{
int tmp = (X[i]%+)%;
for(j=;j<tmp;j++)
{
int x,y;
x = i/m;
y = i%m;
x++; y++;
printf("%d %d\n",x,y);
}
}
}
//printf("\n");
}
return ;
}
/*
10
3 3
0 0 0
0 0 0
0 0 1
1 2
0 0
2 30
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
*/

2. m个未知数的情况

//
// main.cpp
// hdu5755.1
//
// Created by New_Life on 16/8/4.
// Copyright © 2016年 chenhuan001. All rights reserved.
// #include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string> #define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x) ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b) #define ll long long
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 33
using namespace std;
//freopen("din.txt","r",stdin); int a[N][N],X[N];//分别记录增广矩阵和解集
int free_x[N];//记录自由变量
int equ,var;//分别表示方程组的个数和变量的个数 int GCD(int x,int y){
if (y == ) return x;
return GCD(y,x%y);
}
int LCM(int x,int y){
return x/GCD(x,y)*y;
}
void Debug(void)
{
int i, j;
for (i = ; i < equ; i++)
{
for (j = ; j < var + ; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,
//但无整数解,-1表无整数解,-1表示无解,0表示唯一解,大于0表示无穷解,
//并返回自由变元的个数) //ax + by = gcd(a,b)
//传入固定值a,b.放回 d=gcd(a,b), x , y
void extendgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(b==){d=a;x=;y=;return;}
extendgcd(b,a%b,d,y,x);
y-=x*(a/b);
} //Ax=1(mod M),gcd(A,M)==1
//输入:10^18>=A,M>=1
//输出:返回x的范围是[1,M-1]
ll GetNi(ll A,ll MM)
{
ll rex=,rey=;
ll td=;
extendgcd(A,MM,td,rex,rey);
return (rex%MM+MM)%MM;
} int Guass(){
int i,j,k,col;
CL(X,); CL(free_x,); for (k = ,col = ; k < equ && col < var; k++, col++){
int max_r = k;
for (i = k + ; i < equ; ++i){
if (iabs(a[i][col]) > iabs(a[max_r][col])) max_r = i;
}
if (max_r != k){
for (i = k; i < var + ; ++i) swap(a[k][i],a[max_r][i]);
}
if (a[k][col] == ){
//可以随意定义的变量
X[col] = ;//强制赋值为0
free_x[col] = ;
k--;
//cout<<k<<endl;
continue;
}
for (i = k + ; i < equ; ++i){
if (a[i][col] != ){
int lcm = LCM(a[k][col],a[i][col]);
int ta = lcm/iabs(a[i][col]); int tb = lcm/iabs(a[k][col]);
if (a[i][col]*a[k][col] < ) tb = -tb;
for (j = col; j < var + ; ++j){
a[i][j] = ((ta*a[i][j] - tb*a[k][j])%+)%;
}
}
}
}
//Debug();
// 1. 无解的情况:
for (i = k; i < equ; ++i){
if (a[i][col] != ) return -;
}
// 2. 无穷解的情况:
if (k < var){ int num = ,freeidx=;
for (i = k - ; i >= ; --i){
num = ;
int tmp = a[i][var];
for (j = ; j < var; ++j){
if (a[i][j] != && free_x[j]){
num++;
freeidx = j;
}
}
if (num > ) continue;
tmp = a[i][var];
for (j = ; j < var; ++j){
if (a[i][j] && j != freeidx) tmp -= a[i][j]*X[j];
}
//这里也要 int k2 = (tmp%+)%;
int k1 = (a[i][freeidx]%+)%;
if(k1!=)
{
X[freeidx] = k2*(int)GetNi(k1, );
}
else
{
X[freeidx] = ;
//printf("X[%d]为任意?\n",i);
} //X[freeidx] = tmp/a[i][freeidx];
free_x[freeidx] = ;
}
return var - k;
}
// 3. 唯一解的情况:
for (i = k - ; i >= ; --i){
int tmp = a[i][var];
for (j = i + ; j < var; ++j){
tmp -= a[i][j]*X[j];
}
//强行搞一发
int k2 = (tmp%+)%;
int k1 = (a[i][i]%+)%;
if(k1!=)
{
X[i] = k2*(int)GetNi(k1, );
}
else
{
X[i] = ;
//printf("X[%d]为任意?\n",i);
}
//X[i] = tmp/a[i][i];//不整除?
}
return ;
} int g[][];
int save[][][]; int getni(int x)
{
if(x==) return ;
if(x==) return ;
return ;
} void func(int x,int y)
{
g[x][y] = (g[x][y]+)%;
g[x+][y] = (g[x+][y]+)%;
g[x][y+] = (g[x][y+]+)%;
g[x-][y] = (g[x-][y]+)%;
g[x][y-] = (g[x][y-]+)%;
} int main() {
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&g[i][j]);
memset(save,,sizeof(save)); for(int i=;i<=m;i++)
{
save[][i][i] = ;
}
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
for(int k=;k<=m;k++)
{
int tmp = (save[i-][j][k]*+save[i-][j+][k]+save[i-][j-][k]) + save[i-][j][k];
if(k == ) tmp += g[i-][j];
tmp %= ;
save[i][j][k] = getni(tmp);
}
}
} //然后构建矩阵
memset(a,,sizeof(a));
equ = m;
var = m;
for(int j=;j<=m;j++)
{
for(int k=;k<=m;k++)
{
int tmp = save[n][j][k]*+save[n][j+][k]+save[n][j-][k] + save[n-][j][k];
if(k==)
{
tmp += g[n][j];
a[j-][m] = getni(tmp%);
}
else a[j-][k-] = tmp%;
}
}
CL(X,);
CL(free_x,);
int free_num = Guass();
if(free_num == - || free_num == -){ cout<<free_num<<" 错误"<<endl; continue;}
int ans = ;
int saveans[][];
memset(saveans,,sizeof(saveans));
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
int tmp = ;
for(int k=;k<=m;k++)
{
if(k==) tmp += save[i][j][];
else tmp += save[i][j][k]*X[k-];
tmp %= ;
}
ans += tmp;
saveans[i][j] = tmp;
} printf("%d\n",ans);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
for(int k=;k<saveans[i][j];k++)
{
printf("%d %d\n",i,j);
//func(i,j);
}
} // for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++) printf("%d ",g[i][j]);
// printf("\n");
// }
}
return ;
}
/*
10
1 3
0 0 1
3 3
0 0 0
0 0 0
0 0 1
1 2
0 0
2 30
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
*/

hdu 5755(高斯消元——模线性方程组模板)的更多相关文章

  1. HDU.3571.N-dimensional Sphere(高斯消元 模线性方程组)

    题目链接 高斯消元详解 /* $Description$ 在n维空间中给定n+1个点,求一个点使得这个点到所有点的距离都为R(R不给出).点的任一坐标|xi|<=1e17. $Solution$ ...

  2. POJ.2065.SETI(高斯消元 模线性方程组)

    题目链接 \(Description\) 求\(A_0,A_1,A_2,\cdots,A_{n-1}\),满足 \[A_0*1^0+A_1*1^1+\ldots+A_{n-1}*1^{n-1}\equ ...

  3. HDU 2827 高斯消元

    模板的高斯消元.... /** @Date : 2017-09-26 18:05:03 * @FileName: HDU 2827 高斯消元.cpp * @Platform: Windows * @A ...

  4. hdu 5755 2016 Multi-University Training Contest 3 Gambler Bo 高斯消元模3同余方程

    http://acm.hdu.edu.cn/showproblem.php?pid=5755 题意:一个N*M的矩阵,改变一个格子,本身+2,四周+1.同时mod 3;问操作多少次,矩阵变为全0.输出 ...

  5. HDU 3359 高斯消元模板题,

    http://acm.hdu.edu.cn/showproblem.php?pid=3359 题目的意思是,由矩阵A生成矩阵B的方法是: 以a[i][j]为中心的,哈曼顿距离不大于dis的数字的总和 ...

  6. hdu 3915 高斯消元

    http://acm.hdu.edu.cn/showproblem.php?pid=3915 这道题目是和博弈论挂钩的高斯消元.本题涉及的博弈是nim博弈,结论是:当先手处于奇异局势时(几堆石子数相互 ...

  7. [置顶] hdu 4418 高斯消元解方程求期望

    题意:  一个人在一条线段来回走(遇到线段端点就转变方向),现在他从起点出发,并有一个初始方向, 每次都可以走1, 2, 3 ..... m步,都有对应着一个概率.问你他走到终点的概率 思路: 方向问 ...

  8. 题解【AcWing883】高斯消元解线性方程组

    题面 高斯消元模板题. 这里直接讲述一下高斯消元的算法流程: 枚举每一列 \(c\): 找到第 \(c\) 列绝对值最大的一行: 将这一行换到最上面: 将该行的第一个数变成 \(1\): 将下面所有行 ...

  9. HDU 4418 高斯消元解决概率期望

    题目大意: 一个人在n长的路径上走到底再往回,走i步停下来的概率为Pi , 求从起点开始到自己所希望的终点所走步数的数学期望 因为每个位置都跟后m个位置的数学期望有关 E[i] = sigma((E[ ...

随机推荐

  1. 山东理工大学第七届ACM校赛-学区房问题 分类: 比赛 2015-06-26 10:23 89人阅读 评论(0) 收藏

    Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 铁牌狗在学区B有一套面积为S1平方米的房子,现在他为了让后代进化成金牌狗,决定在学区A购 ...

  2. wpf的研究和反思

    WPF的研究和反思 目前是否适合使用wpf      WPF(Windows Presentation Foundation)是微软推出的基于Windows Vista的用户界面框架,属于.NET F ...

  3. TCP三次握手

      TCP协议下,客户的和服务器的连接过程称为“三次握手”   第一次握手:建立连接时,客户的发送SYN包到服务器,并进入SYN_SEND状态,等待服务器确认. 第二次握手:服务器收到SYN包,必须确 ...

  4. CentOS 6.5升级Python2.7

    1.下载并解压Python2.7的源码. . 2.编译与安装Python2.7. ./configure --prefix=/usr/local make && make altins ...

  5. C#实现中国天气网JSON接口测试

    接上一篇,经过反复的查看,最终从这篇文章中找到了一个可用的JSON接口,于是研究了一下中国天气网JSON接口的测试: 和上一篇XML接口测试的原理是一样的,只是需要安装一下Newtonsoft.Jso ...

  6. JS中的call()和apply()方法和bind()

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  7. ContentProvider官方教程(3)ContentResolver查询、遍历 示例

    Retrieving Data from the Provider This section describes how to retrieve data from a provider, using ...

  8. SqlSever基础 delete 删除一个表中的所有数据

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  9. SqlSever基础 datediff 计算两个时间相差多少年份

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  10. Linux的启动过程

    Linux的启动过程,也就是Linux的引导流程,这部分主要是理论知识. Linux的开机启动过程 1.1第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的 ...