洛谷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$的解了。

当然,在计算机里,我们可以编程完成这种操作。

具体地说,对于每一行,

我们要:

  1. 把这一行和下面的一些行进行交换,使得它的对应系数不为0
  2. 消去下面的对应系数

具体我也说不清楚,所以你们还是看代码吧。

#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;
}
posted @ 2018-07-23 13:48  MCH__ds  阅读(307)  评论(0编辑  收藏  举报