hdu 5755(高斯消元——模线性方程组模板)
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(高斯消元——模线性方程组模板)的更多相关文章
- HDU.3571.N-dimensional Sphere(高斯消元 模线性方程组)
题目链接 高斯消元详解 /* $Description$ 在n维空间中给定n+1个点,求一个点使得这个点到所有点的距离都为R(R不给出).点的任一坐标|xi|<=1e17. $Solution$ ...
- 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 ...
- HDU 2827 高斯消元
模板的高斯消元.... /** @Date : 2017-09-26 18:05:03 * @FileName: HDU 2827 高斯消元.cpp * @Platform: Windows * @A ...
- 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.输出 ...
- HDU 3359 高斯消元模板题,
http://acm.hdu.edu.cn/showproblem.php?pid=3359 题目的意思是,由矩阵A生成矩阵B的方法是: 以a[i][j]为中心的,哈曼顿距离不大于dis的数字的总和 ...
- hdu 3915 高斯消元
http://acm.hdu.edu.cn/showproblem.php?pid=3915 这道题目是和博弈论挂钩的高斯消元.本题涉及的博弈是nim博弈,结论是:当先手处于奇异局势时(几堆石子数相互 ...
- [置顶] hdu 4418 高斯消元解方程求期望
题意: 一个人在一条线段来回走(遇到线段端点就转变方向),现在他从起点出发,并有一个初始方向, 每次都可以走1, 2, 3 ..... m步,都有对应着一个概率.问你他走到终点的概率 思路: 方向问 ...
- 题解【AcWing883】高斯消元解线性方程组
题面 高斯消元模板题. 这里直接讲述一下高斯消元的算法流程: 枚举每一列 \(c\): 找到第 \(c\) 列绝对值最大的一行: 将这一行换到最上面: 将该行的第一个数变成 \(1\): 将下面所有行 ...
- HDU 4418 高斯消元解决概率期望
题目大意: 一个人在n长的路径上走到底再往回,走i步停下来的概率为Pi , 求从起点开始到自己所希望的终点所走步数的数学期望 因为每个位置都跟后m个位置的数学期望有关 E[i] = sigma((E[ ...
随机推荐
- 移动端web出现的一系列问题
今天做移动端的web,在做后期处理的时候,发现了非常多的问题.下面我分别列举一下吧~~ 1.移动端浏览器众多,各种浏览器之间的显示等都有差异,很多需要单独处理,于是我需要判断分别是什么浏览器.js代码 ...
- Netfilter/iptables防火墙
http://os.51cto.com/art/201107/273443.htm [51CTO独家特稿]Linux系统管理员们都接触过Netfilter/iptables,这是Linux系统自带的免 ...
- python 使用 redis expire属性设置访问时间间隔
安装redis yum install redis 安装python redis扩展 pip install redis 启动redis,并设定开机自动启动 service redis start c ...
- Android中直播视频技术探究之---摄像头Camera视频源数据采集解析
一.前言 在视频直播中一般都是两种视频数据源,一个是摄像头数据,一个是录制桌面数据,而一般来说美女妹子直播都是来自于摄像头数据,游戏直播都是录制桌面数据的,那么今天就来看看第一个数据源数据采集分析,A ...
- 窗体移动API
//窗体移动API [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport ...
- Date日期比对
Calendar calendar1 = Calendar.getInstance(); Calendar calendar2 = Calendar.getInstance(); calendar1. ...
- windows下mysql自动定时备份bat
@echo off : basedataset ip=192.168.12.41set user=rootset password=12456 set databaseName=test set /a ...
- 在C++工程中设置全局函数
在头文件中对该函数进行全局函数的声明: extern void Test(); 在cpp文件中进行函数的定义: void Test() { MessageBox(NULL,L"调用了C++的 ...
- CodeForces 670D2 Magic Powder 二分
D2. Magic Powder - 2 The term of this problem is the same as the previous one, the only exception — ...
- AutoLayout +Masonary
1, Masonry介绍与使用实践(快速上手Autolayout) http://adad184.com/2014/09/28/use-masonry-to-quick-solve-autolayou ...