一次线性方程组 高斯消元笔记

高斯消元原理

高斯消元用来解如下形式的方程组:

{a1,1x1+a1,2x2++a1,nxn=b1a2,1x1+a2,2x2++a2,nxn=b2an,1x1+an,2x2++an,nxn=bn

首先将所有系数写成系数矩阵:

[a1,1a1,2a1,nb1a2,1a2,2a2,nb2an,1an,2an,nbn]

接下来可以进行初等行列变换,将矩阵消成下三角矩阵。类似这样:

[a1,1a1,2a1,nb10a2,2a2,nb200a3,nb300an,nbn]

然后最后一行就表示 an,nxn=an,n+1,可以解出 xn

然后往回带,解出 xn1,以此类推即可。时间复杂度 O(n3)

void gauss() {
	rep(i, 1, n) {
		rep(j, i, n) if (fabs(a[j][i]) > eps) {
			swap(a[j], a[i]); break;
		} if (fabs(a[i][i]) <= eps) continue;
		rep(j, i + 1, n) {
			if (fabs(a[j][i]) <= eps) continue;
			db inv = (db)a[j][i] / a[i][i];
			rep(k, i, n + 1)
				a[j][k] -= inv * a[i][k];
		}
	}
	for (int i = n; i; i -- ) {
		f[i] = a[i][n + 1] / a[i][i];
		for (int j = i - 1; j; j -- )
			a[j][n + 1] -= a[j][i] * f[i];
	}
}

高斯消元应用

  • 解线性方程组

这个不用我说了吧。。。

  • dp 中用于消元

这个用处非常大。举个栗子:P3232 [HNOI2013] 游走

题意:给定 nm 边无向简单图。要求给每条边重新编号 1m,使得每条边编号不同且从 1n 经过路径的权值和期望尽可能小。

n500,m125000

发现边数很多,所以从点数入手。设 fi 表示第 i 个点被经过的期望次数,那么有:

{f1=(1,v)E,vnfvdegv+1fu=(u,v)E,vnfvdegv+1(u1)

当然,n 号点被我们排除在外,因为到了 n 就停止了。

然后发现,上面的柿子形成了一个 n1 元方程。用高斯消元解方程就可以得到 fu

然后可以得到每条边被经过的期望次数:g(u,v)=fudegu+fvdegv。根据边被经过的期望次数贪心赋权即可。

其他用高斯消元求解 dp 的例题:P4321 随机漫游

  • 矩阵求逆

矩阵 A 的逆矩阵定义为 A1,满足 A1×A=IA1×A=I。其中 I 表示单位矩阵。

求法:将原矩阵 A 右面拼上一个单位矩阵 I。然后对左边一半也就是 A 做初等行列变换消成单位矩阵,同时对右边做左边同样的操作(左边行加右边也加,左边同乘右边也同乘)。最后得到的右半边就是 A1

证明真的不会/kk

int gauss() {
	rep(i, 1, n) {
		rep(j, i, n)
			if (a[j][i] != 0) {
				swap(a[i], a[j]); break;
			}
		if (a[i][i] == 0) return 0;
		rep(j, i + 1, n) {
			if (a[j][i] == 0) continue;
			int inv = a[j][i] * qpow(a[i][i]) % mod;
			rep(k, i, 2 * n) a[j][k] -= inv * a[i][k] % mod,
				a[j][k] = (a[j][k] % mod + mod) % mod;
		}
	}
	rep(i, 1, n) {
		int inv = qpow(a[i][i]);
		rep(j, 1, 2 * n) a[i][j] = a[i][j] * inv % mod;
	}
	dep(i, n, 1) {
		rep(j, 1, i - 1) {
			int inv = a[j][i];
			rep(k, 1, 2 * n) a[j][k] -= a[i][k] * inv % mod,
				a[j][k] = (a[j][k] % mod + mod) % mod;
		}
	} return 1;
}
signed main() {
	read(n); int B = (10 * n + 5) * sizeof(LL);
	rep(i, 0, n + 1) a[i] = (LL*)malloc(B);
	rep(i, 1, n) rep(j, 1, n) read(a[i][j]);
	rep(i, 1, n) a[i][i + n] = 1; int s = gauss();
	if (!s) return puts("No Solution"), 0;
	for (int i = 1; i <= n; i ++ , pc('\n'))
		rep(j, 1, n) write(' ', a[i][j + n]);
	return 0;
}
posted @   Link-Cut-Y  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示