数学知识——高斯消元法和容斥原理
高斯消元法
定义原理
-
内容
消元法是将方程组中的一方程的未知数用含有另一未知数的代数式表示,并将其代入到另一方程中,这就消去了一未知数,得到一解;或将方程组中的一方程倍乘某个常数加到另外一方程中去,也可达到消去一未知数的目的。消元法主要用于二元一次方程组的求解。 -
核心
1)两方程互换,解不变;
2)一方程乘以非零数k,解不变;
3)一方程乘以数k加上另一方程,解不变 。 -
举例介绍
转化为行列式
由行列式求解其中计算过程可能有误,但大体流程是对的
-
总结方法
1)转换行列式- 枚举1~n列,假设当前列为第i列,找到第i列第i行到n行最大的数,将其所在行挪到第i行
- 将第i行乘一个非0数使得第i行第i列元素变为1,然后用第i行与下面所有行进行运算,使下面所有行的第i列元素变为0
2)行列式求解
从第n行开始枚举到第1行假设为第i行,每一行的第i列到第n列,假设为j列都由第j行的相应的首位非0数消为0,最终得到的第n + 1列即为解
例题
输入一个包含 n 个方程 n 个未知数的线性方程组。
方程组中的系数为实数。
求解这个方程组。
下图为一个包含 m 个方程 n 个未知数的线性方程组示例:
输入格式
第一行包含整数 n。
接下来 n 行,每行包含 n+1 个实数,表示一个方程的 n 个系数以及等号右侧的常数。
输出格式
如果给定线性方程组存在唯一解,则输出共 n 行,其中第 i 行输出第 i 个未知数的解,结果保留两位小数。
如果给定线性方程组存在无数解,则输出 Infinite group solutions。
如果给定线性方程组无解,则输出 No solution。
数据范围
1≤n≤100,
所有输入系数以及常数均保留两位小数,绝对值均不超过 100。
输入样例:
3
1.00 2.00 -1.00 -6.00
2.00 1.00 -3.00 -9.00
-1.00 -1.00 2.00 7.00
输出样例:
1.00
-2.00
3.00
n = int(input())
eps = 1e-8
p = []
def gauss() :
r = 0
for c in range(n) :
t = r
for i in range(t + 1, n) :
if p[t][c] < p[i][c] :
t = i
if abs(p[t][c]) < eps :
continue
for i in range(c, n + 1) :
p[t][i], p[r][i] = p[r][i], p[t][i]
for i in range(n, c - 1, -1) :
p[r][i] /= p[r][c]
for i in range(r + 1, n) :
if abs(p[i][c]) < eps :
continue
for j in range(n, c - 1, -1) :
p[i][j] -= p[r][j] * p[i][c]
r += 1
if r < n :
for i in range(r, n) :
if (abs(p[i][n]) > eps) :
return 2
return 1
for i in range(n - 1, -1, -1) :
for j in range(i + 1, n) :###对于第i行的i列不需要被消,其余都要被消
p[i][n] -= p[i][j] * p[j][n]
return 0
for i in range(n) :
p.append(list(map(int, input().split())))
t = gauss()
if t == 1 :
print("Infinite group solutions")
elif t == 2 :
print("No solution")
else :
for i in range(n) :
if abs(p[i][n]) <= 0 :
p[i][n] = 0
print("%.2f"%p[i][n])
容斥原理
简介
在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
公式
例题
给定一个整数 n 和 m 个不同的质数 p1,p2,…,pm。
请你求出 1∼n 中能被 p1,p2,…,pm 中的至少一个数整除的整数有多少个。
输入格式
第一行包含整数 n 和 m。
第二行包含 m 个质数。
输出格式
输出一个整数,表示满足条件的整数的个数。
数据范围
1≤m≤16,
1≤n,pi≤10^9
输入样例:
10 2
2 3
输出样例:
7
n, m = map(int, input().split())
p = list(map(int, input().split()))
res = 0
for i in range(1, 1 << m) :
t = 1
s = 0
for j in range(m) :
if i >> j & 1 :
if t * p[j] > n :
t = -1
break
t *= p[j]
s += 1
if t != -1 :
if s % 2 :
res += n // t
else :
res -= n // t
print(res)
对于枚举1~2^m的组合数,可以用m二进制来枚举,学到了。1移m位,然后枚举1 ~ 2^m中所有数,每一位可以用1~m移位来求
总结
数学知识告一段落,数学果然烧脑子
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!