题意

题目描述

给定一个线性方程组,对其求解

输入输出格式

输入格式:

第一行,一个正整数\(n\)

第二至\(n+1\)行,每行\(n+1\)个整数,为\(a_1, a_2 \cdots a_n\)和\(b\),代表一组方程。

输出格式:

共n行,每行一个数,第\(i\)行为\(x_i\)(保留2位小数)

如果不存在唯一解,在第一行输出"No Solution".

输入输出样例

输入样例#1:

3

1 3 4 5

1 4 7 3

9 3 2 2

输出样例#1:

-0.97

5.18

-2.39

说明

\(1 \leq n \leq 100, \left | a_i \right| \leq {10}^4 , \left |b \right| \leq {10}^4\)

分析

参照_皎月半洒花的题解。

emmmm这个消元方式其实严格来说是可行性算法……而不是优化性算法……不过话说由于我太蒟蒻了,所以并不知道什么更优的算法(#滑稽)

嗯,其实这个算法是\(O(n^3)\)的算法,需要一些矩阵及行列式的知识……那么由本蒟蒻来记录一下这个算法吧!

那么假设有一个线性方程组是长这样的:

\[\begin{Bmatrix} 3x & + & 2y &+& z &=&10 \\5x & + & y &+& 6z &=&25 \\2x & + & 3y &+& 4z &=&20\end{Bmatrix}
\]

emmm这就是一个很简单的三元一次方程,让我们想想常规方法该怎么做(先不谈code)

初中老师说过:我们可以加减消元或者代入消元,但是我们需要在程序里实现的时候,需要一种有规律可循的算法。所以我们选择加减消元,但用代入消元回带。

整体思路就是我们可以先在某一个式子里,用这个式子的\(x\)消去其他式子里的\(x\),然后在剩下的两个式子里再选择一个式子里的\(y\),用这个\(y\)消去最后剩下的式子里的\(y\)。那么现在最后一个方程里就只有一个未知数\(z\)了。倘若\(z\)的系数是1,那么我们就可以直接得出答案来了(别觉得这句话是废话)。

比如刚才这个方程,我们用第二个式子去消1、3式里的$x:

\[\begin{Bmatrix} 0\times x & + & \frac{7}{5}y &+& (-\frac{13}{5}z) &=&-5 \\5x & + & y &+& 6z &=&25 \\0\times x & + & \frac{13}{5}y &+& \frac{8}{5}z &=&10\end{Bmatrix}
\]

整理之后再用第三个式子里的\(y\)消去第一个式子里的\(y\)(注意,由于第二个式子作为消元用式,所以接下来的运算不再考虑二式):

\[\begin{Bmatrix}0\times y &+& (-\frac{225}{65}z) &=&-\frac{135}{13} \\ \frac{13}{5}y &+& \frac{8}{5}z &=&10\end{Bmatrix}
\]

那么我们发现在1式中只剩下一个未知数了,那么就可解得:

\(z=3\)

带回三式里解出

\(y=2\)

再将\(x\)、\(y\)带回最早被消掉的二式里,解得

\(x=1\)

好像这个方法再数学逻辑上讲是特别麻烦的,但是却是一个通用性强的方法qwq

那么放在程序实现上来讲,我们可以先用一个n \times (n+1)n×(n+1)的矩阵来记录每一个式子的系数以及结果。譬如上式就可以用矩阵表示成这样:

\[\begin{Bmatrix} 3& 2 & 1 &|& 10 \\5 & 1 & 6 &|& 25 \\2 & 3 & 4 &|&20\end{Bmatrix}
\]

左边记录系数,右边记录每个式子的结果。

那么首先我们需要用第一列中(所有的\(x\)中)系数最大的来消其他两个式子。而这里为了方便起见,我们将这个选中的系数置为1,方便上例中地不断带回原式的操作(这样在回带的时候就可以不考虑原本的系数了)。

由于最多也只能用double型存储,所以必然会有精度误差。但如果我们每次都选用最大系数的来消掉其他系数,就可以最大程度地来减小误差。以下是一种不严谨地、适合意会的证明(选读):

假设我们现在在处理第nn个未知数,此时在众多的未知数nn中,他们的系数分别是\(k_1 k_2 k_3 k_ 4\dots k_m\),那么考虑,在选完\(k_i\)之后,下面我们要进行的是把\(k_i\)消成1。那么此时对于第ii行的其他的系数以及结果我们都要除以\(k_i\) 。

之后呢?之后我们要进行的操作是用这个式子来消掉其他式子里的该未知数啊qwq。如果要这么操作肯定会让其他式子别的未知数的系数,减去当前式子的别的未知数的系数乘上某个值(事实上假设选择含\(k_i\)的式子,则对于每个式子\(j\)而言,每个系数减去当前系数的倍数,这个倍数应该为\(k_j\)那么这样看来,对于当次用来消元的式子的每个系数\(q_{i1}q_{i2}q_{i3}q_{i4} ……q_{iw}\) (假设当前元的系数是\(q_{i1}\)而言,对于每一个其他式子的该项系数\(q_{jw}\),都需要让\(q_{jw}\)变成

\[q_{jw}-\frac{q_{j1}}{q_{i1}} \times q_{iw}
\]

那么我们观察这个式子,\(q_{i1}\)越大,\(\frac{q_{j1}}{q_{i1}}\)期望越小,那么我们考虑,这个值越小,我们就约可以把它看作一个“基本单位”。从而我们就使得减出来的值失精程度越低,最后即可保证数据是从期望上来讲最精确。

嗯,讲的很麻烦,大家挑重点看吧(或者只看最后一个自然段)

在置为1之后,我们需要来用这个式子去消其他的式子(别忘了每个式子的结果也要消)。那么在最后,我们只需要将这个矩阵的最右下角(也就是最后一个元的实际值)不断回带即可。

时间复杂度\(O(n^3)\)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
co double eps=1e-7;
double map[111][111],ans[111];
int main(){
// freopen(".in","r",stdin),freopen(".out","w",stdout);
int n=read<int>();
for(int i=1;i<=n;++i)
for(int j=1;j<=n+1;++j) read(map[i][j]);
for(int i=1;i<=n;++i){
int r=i;
for(int j=i+1;j<=n;++j)
if(fabs(map[r][i])<fabs(map[j][i])) r=j;
if(fabs(map[r][i])<eps){
puts("No Solution");
return 0;
}
if(i!=r) std::swap(map[i],map[r]);
double div=map[i][i];
for(int j=i;j<=n+1;++j) map[i][j]/=div;
for(int j=i+1;j<=n;++j){
div=map[j][i];
for(int k=i;k<=n+1;++k) map[j][k]-=map[i][k]*div;
}
}
ans[n]=map[n][n+1];
for(int i=n-1;i>=1;--i){
ans[i]=map[i][n+1];
for(int j=i+1;j<=n;++j) ans[i]-=(map[i][j]*ans[j]);
}
for(int i=1;i<=n;++i) printf("%.2lf\n",ans[i]);
return 0;
}

LG3389 【模板】高斯消元法的更多相关文章

  1. LG3389 「模板」高斯消元法 高斯消元

    问题描述 LG3389 题解 高斯消元,是用来解\(n\)元一次方程组的算法,时间复杂度\(O(n^3)\) 这样就构造出了这个方程组的矩阵 目标就是把这个矩阵左边\(n \times n\)消为单位 ...

  2. 高斯消元法(Gauss Elimination)【超详解&模板】

    高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵.高斯消元法的原理是:若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组. ...

  3. 洛谷P3389 【模板】高斯消元法

    P3389 [模板]高斯消元法 题目背景 Gauss消元 题目描述 给定一个线性方程组,对其求解 输入输出格式 输入格式: 第一行,一个正整数 n 第二至 n+1行,每行 n+1 个整数,为a1​,a ...

  4. 题解 P3389 【【模板】高斯消元法】

    题解 P3389 [[模板]高斯消元法] 看到大家都没有重载运算符,那我就重载一下运算符给大家娱乐一下 我使用的是高斯-约旦消元法,这种方法是精度最高的(相对地) 一句话解释高斯约旦消元法: 通过加减 ...

  5. 「LuoguP3389」【模板】高斯消元法

    题目背景 Gauss消元 题目描述 给定一个线性方程组,对其求解 输入输出格式 输入格式: 第一行,一个正整数 nn 第二至 n+1n+1行,每行 n+1n+1 个整数,为a_1, a_2 \cdot ...

  6. 洛谷——P3389 【模板】高斯消元法

    P3389 [模板]高斯消元法 以下内容都可省略,直接转大佬博客%%% 高斯消元总结 只会背板子的蒟蒻,高斯消元是什么,不知道诶,看到大佬们都会了这个水题,蒟蒻只好也来切一切 高斯消元最大用途就是解多 ...

  7. (模板)poj2947(高斯消元法解同余方程组)

    题目链接:https://vjudge.net/problem/POJ-2947 题意:转换题意后就是已知m个同余方程,求n个变量. 思路: 值得学习的是这个模板里消元用到lcm的那一块.注意题目输出 ...

  8. (模板)poj1681 高斯消元法求异或方程组(无解、唯一解、多解)

    题目链接:https://vjudge.net/problem/POJ-1681 题意:类似于poj1222,有n×n的01矩阵,翻转一个点会翻转其上下左右包括自己的点,求最少翻转多少点能使得矩阵全0 ...

  9. [Luogu 3389]【模板】高斯消元法

    Description 给定一个线性方程组,对其求解 Input 第一行,一个正整数 n 第二至 n+1 行,每行 n+1 个整数,为a1,a2⋯an和 b,代表一组方程.1​​,a​2​​⋯a​n​ ...

随机推荐

  1. ng-深度学习-课程笔记-3: Python和向量化(Week2)

    1 向量化( Vectorization ) 在逻辑回归中,以计算z为例,$ z =  w^{T}+b $,你可以用for循环来实现. 但是在python中z可以调用numpy的方法,直接一句$z = ...

  2. 《高性能CUDA应用设计与开发》--笔记

    第一章 1.2 CUDA支持C与C++两种编程语言,该书中的实例采取的是Thrust数据并行API,.cu作为CUDA源代码文件,其中编译器为ncvv.   1.3 CUDA提供多种API: 数据并行 ...

  3. php 用户向微信发送信息

    1:制作微信菜单栏 <?phpheader("Content-type: text/html; charset=utf-8");function request_post($ ...

  4. php 发送邮件类

    //******************** 配置信息 ********************************            $smtpserver = "smtp.263 ...

  5. 20145326 《Java程序设计》课程总结

    每周读书笔记链接汇总 20145326第1周学习总结 20145326第2周学习总结 20145326第3周学习总结 20145326第4周学习总结 20145326第5周学习总结 20145326第 ...

  6. LCD1602小程序

    1显示数据 typedef struct { unsigned long int mL_data; unsigned long int L_data; unsigned long int M3_dat ...

  7. linux kernel 提示VFS: Cannot open root device "mmcblk0p1" or unknown-block(179,1): error -19等信息后发生panic

    一.背景 文件系统安装在sd卡的第一个分区中,使用的是ext4文件系统,linux内核版本为4.14 二.思考 在内核启动之前,uboot给内核传递了参数root=/dev/mmcblk0p1,但是为 ...

  8. HDU6447 网络赛 YJJ's Salesman(DP + 线段树)题解

    思路:若用dp[i][j]表示走到(i,j)的最大值,那么dp[i][j] = max(dp[i - 1][j],dp[i][j - 1],dp[i - 1][j - 1] + v),显然O(n^2) ...

  9. UOJ #122 【NOI2013】 树的计数

    题目链接:树的计数 这道题好神啊……正好有人讲了这道题,那么我就写掉吧…… 首先,为了方便考虑,我们可以把节点重标号,使得\(bfs\)序变成\(1,2,3,\dots,n\),那么显然树的深度就是\ ...

  10. javaScript 真经 小感 this 指向

    编程世界只存在两种基本元素:一个是数据.一个是代码. (能写代码算入门,能处理复杂场景或者数据算合格,能不变应万变是不朽) 最流行的编程思想莫过于面向对象编程,因为面向对象编程思想把数据和代码结合成统 ...