[算法] 高斯消元及其应用
主要问题
对于一个线性的方程组求解。
假设这个方程有 个,则时间复杂度为 。
有些题目的 状态有后效性,但是对于线性的方程,可以用高斯消元进行计算。
解决方法
高斯消元法的思路是:通过消元运算,直到得到一个只关于 的式子,只关于 的式子,只关于 的式子,然后回代计算即可。
如下:最初有一个 元线性方程
将上述方程转换为
最后通过减法消去后 个方程的 :
如此,对于剩下的 个方程又是一个新的线性方程求解问题,继续递归求解,最后回代。
若对于当前的子问题中,有一次计算中的 就已经消失了,那么原问题中的这一未知数没有唯一解。
若当前中存在一个方程的各项系数都为 ,且该条方程的常数项不为 ,则一定无解。
当然,代码具体实现的时候并不需要写递归,直接用循环模拟即可。
实现中还有一个问题,每次求解的 是否会对答案产生影响?
可以发现,若 太小,那么会导致精度问题,所以每次需要选取主元素:最大的 所有方程以它为基础来进行消元。
- Code:
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
#define eps 1e-7
void Read(int &n) {
n = 0; bool f = 0; char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = 1;
c = getchar();
}
while (c >= '0' && c <= '9') {
n = (n << 1) + (n << 3) + (c ^ 48);
c = getchar();
}
if (f) n = -n;
}
const int MAXN = 1e2 + 5;
double a[MAXN][MAXN], ans[MAXN];
int n;
int main() {
Read(n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n + 1; j++) scanf("%lf", &a[i][j]);
for (int i = 1; i <= n; i++) {
int r = i;
for (int j = i + 1; j <= n; j++)
if (fabs(a[r][i]) < fabs(a[j][i])) r = j;//选取主元素
if (fabs(a[r][i]) < eps) return printf("No Solution"), 0;//不存在唯一解
if (i != r) swap(a[i], a[r]);
double tmp = a[i][i];//带入消元
for (int j = i; j <= n + 1; j++) a[i][j] /= tmp;
for (int j = i + 1; j <= n; j++) {
double tmp = a[j][i];
for (int k = i; k <= n + 1; k++) a[j][k] -= a[i][k] * tmp;
}
}
ans[n] = a[n][n + 1];//回代求解
for (int i = n - 1; i >= 1; i--) {
ans[i] = a[i][n + 1];
for (int j = i + 1; j <= n; j++) ans[i] -= a[i][j] * ans[j];
}
for (int i = 1; i <= n; i++) printf("%.2lf\n", ans[i]);
return 0;
}
[JSOI2008]球形空间产生器
题目大意
在 维空间中,给出 个点,求出圆心的坐标。
规定:
- 球心:到球面上任意一点距离都相等的点。
- 距离:设两个 维空间上的点 的坐标为 ,则AB的距离定义为:
思路
设坐标数组为 ,由题意得:
化简得:
将常数项与未知数分离:
等价转化为了 个线性方程,求解即可。
Code
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
#define eps 1e-7
const int MAXN = 1e2 + 5;
double a[MAXN][MAXN], b[MAXN][MAXN], ans[MAXN];
int n;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n + 1; i++)
for (int j = 1; j <= n; j++) scanf("%lf", &b[i][j]);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
a[i][j] = 2 * (b[i][j] - b[i + 1][j]);
a[i][n + 1] += b[i][j] * b[i][j] - b[i + 1][j] * b[i + 1][j];
}
}
for (int i = 1; i <= n; i++) {
int r = i;
for (int j = i + 1; j <= n; j++)
if (fabs(a[r][i]) < fabs(a[j][i])) r = j;
if (i != r) for (int j = 1; j <= n + 1; j++) swap(a[i][j], a[r][j]);
double tmp = a[i][i];
for (int j = i; j <= n + 1; j++) a[i][j] /= tmp;
for (int j = i + 1; j <= n; j++) {
double tmp = a[j][i];
for (int k = i; k <= n + 1; k++) a[j][k] -= a[i][k] * tmp;
}
}
ans[n] = a[n][n + 1];
for (int i = n - 1; i >= 1; i--) {
ans[i] = a[i][n + 1];
for (int j = i + 1; j <= n; j++) ans[i] -= a[i][j] * ans[j];
}
for (int i = 1; i <= n; i++) printf("%.3lf ", ans[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具