这只是一个目录
引言:
此算法为作者突发奇想而写,虽说是算法,但是实际上需要计算机来执行的部分并不多,更多的是通过人脑用数学方法来优化问题,将优化过的问题通过计算机的高性能实现穷举。
(萌新第一次写博客,不喜轻喷QAQ)
原题:
鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?译文:
一只公鸡值五钱,一只母鸡值三钱,三只小鸡值一钱。用一百钱买一百只鸡,求公鸡、母鸡、小鸡各几只。
一、思路
- 思想:通过数学方法简化问题(方程),将简化后的方程交由计算机进行处理。
- 主要操作:在原问题中提取出非齐次线性方程组,后用矩阵运算求其通解,最后使用程序遍历通解、得到结果。
二、具体操作
1、数学运算部分:
(1)、提取题目条件
-
公鸡的总价+母鸡的总价+小鸡的总价=100元
-
公鸡只数+母鸡只数+小鸡只数=100只
-
隐含条件:只数只能为非负整数。
设公鸡只数为
x
x
x,母鸡只数为
y
y
y,小鸡只数为
z
z
z,则可得方程组:
{
5
x
+
3
y
+
1
/
3
z
=
100
x
+
y
+
z
=
100
\begin{cases} 5x+3y+1/3z=100\\ x+y+z=100 \end{cases}
{5x+3y+1/3z=100x+y+z=100
为方便后续处理,易得:
{
15
x
+
9
y
+
z
=
300
x
+
y
+
z
=
100
\begin{cases} 15x+9y+z=300\\ x+y+z=100 \end{cases}
{15x+9y+z=300x+y+z=100
(2)、线性代数运算
已知方程组:
{
15
x
+
9
y
+
z
=
300
x
+
y
+
z
=
100
\begin{cases} 15x+9y+z=300\\ x+y+z=100 \end{cases}
{15x+9y+z=300x+y+z=100
设其增广矩阵为:
(
A
∣
b
)
=
(
15
9
1
300
1
1
1
100
)
(A|b)= \left( \begin{array}{ccc|c} 15&9&1&300\\ 1&1&1&100 \end{array} \right)
(A∣b)=(1519111300100)
对增广矩阵矩阵进行初等行变换可得:
(
A
∣
b
)
→
(
1
1
1
100
0
−
6
−
14
−
1200
)
(A|b)→ \left( \begin{array}{ccc|c} 1&1&1&100\\ 0&-6&-14&-1200 \end{array} \right)
(A∣b)→(101−61−14100−1200)
易得系数矩阵的秩
r
=
2
r=2
r=2 。设自由变量
z
=
3
k
z = 3k
z=3k ,带入可得:
{
x
+
y
+
3
k
=
100
−
6
y
−
14
∗
3
k
=
−
1200
\begin{cases} x+y+3k=100\\ -6y-14*3k=-1200 \end{cases}
{x+y+3k=100−6y−14∗3k=−1200
则非齐次线性方程组的通解为:
{
x
=
−
100
+
4
k
y
=
200
−
7
k
z
=
3
k
\begin{cases} x=-100+4k\\ y=200-7k\\ z=3k \end{cases}
⎩
⎨
⎧x=−100+4ky=200−7kz=3k
已知
x
x
x ,
y
y
y ,
z
z
z 均为非负整数,则
k
k
k 只可取整数。
2、程序部分(Python)
'''计数器初始化'''
k=0
'''判断x,y,z是否为非负整数的函数'''
def Int(num):
if int(num) == num and int(num) >= 0:
return True
else:
return False
'''主函数'''
'''当3*k,既z的数值大于100时,循环退出'''
while 3*k <= 100:
'''遍历非齐次线性方程组的通解'''
x = 100 * (-1) + k * 4
y = 100 * 2 + k * (-7)
z = 100 * 0 + k * 3
'''判断三个个数是否同为非负整数,当同为非负整数时打印当前x,y,z值'''
if Int(x) and Int(y) and Int(z):
print(x,y,z)
'''通解计数器递增'''
k += 1
运行结果:
0 25 75
4 18 78
8 11 81
12 4 84
程序部分Q&A:
Q1.k可以为负值吗?
A:在方程组通解中, k k k 可以为负值,但在该函数中不可,方程组关于元素 z z z 的通解为 z = 3 k z=3k z=3k 而 z z z 为非负整数,所以 k k k 只可取非负整数.
Q2. 循环退出条件可以用 x x x , y y y 来表示吗?
A:可以,但需要改动。 x x x 可以直接用 x < = 100 x<=100 x<=100 ,但y需要表示为 y > = 0 y>=0 y>=0 ,究其原因,由通解易得 x ( k ) x(k) x(k) 为递增函数,而 y ( k ) y(k) y(k) 为递减函数。
三、算法分析
1、空间复杂度
该算法在运行过程中没有创建临时变量,固空间复杂度为 O ( 1 ) O(1) O(1)
2、时间复杂度
算法中只含有单层k次循环语句,固: 最佳时间复杂度 = 最差时间复杂度 = 平均时间复杂度 = O ( n ) {最佳时间复杂度}={最差时间复杂度}={平均时间复杂度}=O(n) 最佳时间复杂度=最差时间复杂度=平均时间复杂度=O(n)
相较于暴力穷举法的时间复杂度为 O ( n 3 ) O(n^{3}) O(n3) ,该算法能显著降低时间复杂度。
四、问题分析
1、人脑vs电脑
该算法的思路为通过人脑来优化问题,减小对机器性能的压力。在小型问题求解中,程序并不会对机器性能带来过大的压力,相反会通过人脑进行大量的运算,所以并非优解。但在大型问题的求解中(如万钱买万鸡,n钱买n鸡以及类似问题),该算法 O ( n ) O(n) O(n) ,相较于 O ( n 3 ) O(n^{3}) O(n3) 可大量减少对机器性能的压力。故该程序更适合大型问题的求解。
2、可读性
该算法代码部分简介、一目了然,但是方程组部分难以理解,需要数学语言描述。但碍于大部分IDE不支持数学语言的注释,为提高可读性,需要在程序外额外添加数学语言注释(如上文 数学运算部分)。