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[ ...
随机推荐
- poj3667 Hotel
此题不难却易出错,很能考察思维的严谨性. 指定ll为区间内左端顶格数的连续可利用房间,rr为右端顶格数的数值,mm为区间内最长的连续可利用房间数. 在查询的时候,由于要返回最靠左的区间左端点,使得在该 ...
- (POJ2635)The Embarrassed Cryptographer(大数取模)
The Embarrassed Cryptographer Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13041 Accep ...
- 山东理工大学第七届ACM校赛-飞花的鱼塘 分类: 比赛 2015-06-26 10:30 43人阅读 评论(0) 收藏
飞花的鱼塘 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 一日,飞花壕在稷下湖游玩,忽然,飞花巨有了一个养鱼的想法,于是,他大手 ...
- Who's in the Middle 分类: POJ 2015-06-12 19:45 11人阅读 评论(0) 收藏
Who's in the Middle Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 34155 Accepted: 1 ...
- hiho(1081),SPFA最短路,(非主流写法)
题目链接:http://hihocoder.com/problemset/problem/1081 SPFA求最短路,是不应-羁绊大神教我的,附上头像. 我第一次写SPFA,我用的vector存邻接表 ...
- linux Centos 6.5 FTP服务原理及vsfptd的安装、配置(转)
本篇随笔将讲解FTP服务的原理以及vsfptd这个最常用的FTP服务程序的安装与配置... 一.FTP服务原理 FTP(File Transfer Protocol)是一个非常古老并且应用十分广泛的文 ...
- 开机logo切换逻辑深入研究
增加暗码命令切换开关机logo功能 u-boot logo显示原理: 1.----Little Kernel会在platform_early_init阶段首先会获取lcm params,其工作流 程就 ...
- CocoaPods的安装[转载]
[转载] 原地址http://www.tuicool.com/articles/7VvuAr3 觉得很好,很有用 iOS 最新版 CocoaPods 的安装流程 1.移除现有Ruby默认源 $gem ...
- Cheatsheet: 2013 07.01 ~ 07.08
.NET The overhead of async/await in NET 4.5 await Task, Task.Wait and Friends 350 Interview Question ...
- Map Columns From Different Tables and Create Insert and Update Statements in Oracle Forms
This is one of my most needed tool to create Insert and Update statements using select or alias from ...