洛谷P3389 【模板】高斯消元法
传送门
题意
给定一个线性方程组
$$\begin{cases} a_{11}x_1+a_{12}x_2+\cdots+a_{1n}x_n=b_1\\a_{21}x_1+a_{22}x_2+\cdots+a_{2n}x_n=b_1\\...\\a_{n1}x_1+a_{n2}x_2+\cdots+a_{nn}x_n=b_n\end{cases}$$
求$x_1,x_2,\cdots,x_n$的解。
$n\leq 100$
题解
我相信你会解一个三元一次方程组,例如
$$\begin{cases}3x_1+4x_2+5x_3=5\\-1x_1-5x_2-9x_3=4\\0x_1+5x_2-2x_3=-3\end{cases}$$
你会怎么解这个方程?当然,一般的,你会把一些系数化成0——
$$\begin{cases}3x_1+4x_2+5x_3=5\\0x_1-\frac{11}{3}x_2-\frac{22}{3}x_3=\frac{17}{3}\\0x_1+0x_2-12x_3=\frac{52}{11}\end{cases}$$
然后就可以得出三个$x$的解了。
当然,在计算机里,我们可以编程完成这种操作。
具体地说,对于每一行,
我们要:
- 把这一行和下面的一些行进行交换,使得它的对应系数不为0
- 消去下面的对应系数
具体我也说不清楚,所以你们还是看代码吧。
#include <bits/stdc++.h> using namespace std; typedef long double ld; const ld eps=1e-6; int n; ld a[105][105], ans[105]; inline void swapLine(int x,int y) { for (int i=1; i<=n+1; i++) {int t=a[x][i]; a[x][i]=a[y][i]; a[y][i]=t;} } inline ld labs(ld x) {return x<0?-x:x;} void gauss(int x) { if (x==n) { //just ok for (int i=1; i<=n; i++) if (labs(a[i][i]) < eps) {puts("No Solution");exit(0);} ans[n] = a[n][n+1] / a[n][n]; for (int i=n-1; i; i--) { ld val=0; for (int j=i+1; j<=n; j++) val+=a[i][j]*ans[j]; ans[i]=(a[i][n+1]-val) / a[i][i]; } for (int i=1; i<=n; i++) printf("%.2Lf\n", ans[i]); exit(0); } if (!a[x][x]) { int i; for (i=x+1; i<=n; i++) if (a[i][x]) { swapLine(1, i); break; } if (i > n) { puts("No Solution"); exit(0); } } for (int i=x+1; i<=n; i++) if (a[i][x]) { //XIAO ld p=-a[i][x]/a[x][x]; a[i][x]=0; for (int j=x+1; j<=n+1; j++) a[i][j]+=p*a[x][j]; } gauss(x+1); } int main() { scanf("%d", &n); for (int i=1; i<=n; i++) { for (int j=1; j<=n+1; j++) scanf("%Lf", &a[i][j]); } gauss(1); return 0; }