趣味算法Python实现(五)

1.m元素集合的n个元素子集

        假设有个集合拥有m个元素,任意的从集合中取出n个元素,则这n个元素所形成的可能子集
有那些?
        
        假设有集合,包含5个元素{1,2,3,4,5},取出3个元素的可能子集如下:
        
        {1 2 3}、{1 2 4 }、{1 2 5}、{1 3 4}、{1 3 5}、{1 4 5}、{2 3 4}、{2 3 5}、{2 4 5}、{3 4 5}
        观察集合我们可以得出一些结论:
        如果最右一个元素小于5,则依次不断加1,如果右边一位已至最大值,则加1的位置往左移
每次加1的位置往左移后,必须重新调整右边的元素为递减顺序。因此可以使用变量p记录位置,初
始值设定为n-1,p位置的值小于m,则不断+1,大于m之后,p-1即左移。
        
实现:
MAX = 20
set = []
m = 5
n = 3

for i in range(m):
    set.append(i + 1)

for i in range(n):
    print('{} '.format(set[i]), end='')

print('')

position = n - 1

while True:
    if set[n - 1] == m:
        position -= 1
    else:
        position = n - 1
    set[position] += 1

    for i in range(position + 1, n):
        set[i] = set[i - 1] + 1

    for i in range(n):
        print('{} '.format(set[i]), end='')
    print('')

    if set[0] >= m - n + 1:
        break

2.数字拆解

        首先我们来看一下数字拆解方式:

        3的拆法:3 = 2+1 = 1+1+1

        4的拆法:4 = 3 + 1 = 2 + 2 = 2 + 1 + 1 = 1 + 1 + 1 + 1

        5的拆法:5 = 4 + 1 = 3 + 2 = 3 + 1 + 1 = 2 + 2 + 1 = 2 + 1 + 1 + 1 = 1 + 1 +1 +1 +1

  依次类推,给出一个数字num拆解方法个数是多少?

        以5的拆法为例,假设数字n的拆法有f(n)个,使用f(x,y)为使用y以下的数字来拆解x的方法个

数,则:

        f(5) = f(4, 1) + f(3,2) + f(2,3) + f(1,4) + f(0,5),其中f(1, 4) = f(1, 3) + f(1, 2) + f(1, 1),但是使

用1的数字来拆解1没有意义,所以f(1, 4) = f(1, 1),而同样的,f(0, 5)会等于f(0, 0),所以:

f(5) = f(4, 1) + f(3,2) + f(2,3) + f(1,1) + f(0,0) 依照以上的说明,使用动态程式规画(Dynamic

programming)来进行求解,其中f(4,1)其实就是f(5-1, min(5-1,1)),

f(x, y)就等于f(n-y, min(n-x, y)),其中n为要拆解的数字,而min()表示取两者中较小的数。

实现如下:

NUM = 5
DEBUG = 0
table = [[0 for _ in range(NUM // 2 + 1)] for _ in range(NUM)]
count = 0
result = 0

print("数字拆解")
print("3 = 2+1 = 1+1+1 所以3有三种拆法")
print("4 = 3 + 1 = 2 + 2 = 2 + 1 + 1 = 1 + 1 + 1 + 1")
print("共五种")
print("5 = 4 + 1 = 3 + 2 = 3 + 1 + 1")
print(" = 2 + 2 + 1 = 2 + 1 + 1 + 1 = 1 + 1 +1 +1 +1")
print("共七种")
print("依此类推,求 {} 有几种拆法?".format(NUM))

for i in range(NUM):
    table[i][0] = 1  # 任何数以0以下的数拆解必只有1种
    table[i][1] = 1  # 任何数以1以下的数拆解必只有1种

for i in range(2, NUM+1):
    for j in range(2, i+1):
        if i+j > NUM:
            continue
        count = 0
        for k in range(1, j+1):
            if i-k >= k:
                s = k
            else:
                s = i-k
            count += table[i-k][s]

        table[i][j] = count

for k in range(1, NUM+1):
    if NUM-k >= k:
        s = k
    else:
        s = NUM-k
    result += table[NUM-k][s]

print("result: {}".format(result))

3.得分排行

        假设老师按照学生的学号输入成绩,现希望在输入完毕后自动显示学生分数的排行。

这里我们使用数组来帮助我们快速排序。

实现如下:

MAX = 100
MIN = 0
juni = [0 for _ in range(MAX+3)]
i = 0
score = [100,90,80,95,93,85,80,-1]
count = 6
for i in range(count):
    juni[score[i]] += 1

juni[MAX+1] = 1

for i in reversed(range(MIN, MAX+1)):
    juni[i] = juni[i] + juni[i+1]

print("得分\t排行")

for i in range(count):
    print("{}\t{}".format(score[i], juni[score[i]+1]))

4.多维矩阵转一维矩阵

        为了节省空间或是方便计算,很多时间我们会选择使用一维矩阵存储多维矩阵。以二维矩阵

转一维矩阵为例,索引值由0开始,在由二维阵列转一维阵列时,我们有两种方式:「以列

Row)为主」或「以行(Column)为主」。以列为主的二维阵列要转为一维阵列时,是将二维

阵列由上往下一列一列读入一维阵列,此时索引的对应公式如下所示,其中rowcolumn是二维阵

列索引,loc表示对应的一维阵列索引:

        loc = column + row*行数
以行为主的二维阵列要转为一维阵列时,是将二维阵列由左往右一行一行读入一维阵列,此时索引
的对应公式如下所示:
        
        loc = row + column*列数
        如果是三维阵列,则公式如下所示,其中i(个数u1)、 j(个数u2)、 k(个数u3)分别表示
三维阵列的三个索引:
        以列为主:loc = i*u2*u3 + j*u3 + k
        
        以行为主:loc = k*u1*u2 + j*u1 + i
        
        更高维度依次类推。

实现如下:

arr1 = [[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]]
arr2 = [0]*12
print("原二维矩阵:")
for row in range(3):
    for col in range(4):
        print("{} ".format(arr1[row][col]),end="")
    print("")

print("第一种:")
for row in range(3):
    for col in range(4):
        i = col + row * 4
        arr2[i] = arr1[row][col]
for i in range(12):
    print("{} ".format(arr2[i]),end="")

print("")
print("第二种:")
for row in range(3):
    for col in range(4):
        i = col * 3 + row
        arr2[i] = arr1[row][col]
for i in range(12):
    print("{} ".format(arr2[i]),end="")

5.2(2N+1)魔方阵

        方阵的维度整体来看是偶数,但是其实是一个奇数乘以一个偶数,例如6X6 ,其中 6=2X3
我们也称这种方阵与单偶数方阵。

实现如下:

N = 6

def swap(x, y):
    t = x
    x = y
    y = t

def magic_o(square, n):
    row = 0
    column = n // 2
    for count in range(1, n*n+1):
        square[row][column] = count
        square[row+n][column+n] = count + n*n
        square[row][column+n] = count + 2*n*n
        square[row+n][column] = count + 3*n*n
        if count%n == 0:
            row += 1
        else:
            if row == 0:
                row = n-1
            else:
                row = row - 1
            if column == n-1:
                column = 0
            else:
                column = column + 1

def exchange(x, n):
    m = n // 4
    m1 = m - 1
    for i in range(n//2):
        if i != m:
            for j in range(m):
                swap(x[i][j], x[n//2+i][j])
            for j in range(m1):
                swap(x[i][n-1-j], x[n//2+i][n-1-j])
        else:
            for j in range(m+1):
                swap(x[m][j], x[n//2+m][j])
            for j in range(m1):
                swap(x[m][n-1-j], x[n//2+m][n-1-j])

if __name__ == "__main__":
    square = [[0 for _ in range(N)] for _ in range(N)]
    magic_o(square, N//2)
    exchange(square, N)

    for i in range(N):
        for j in range(N):
            print("{} ".format(square[i][j]), end="")
        print('')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苜蓿花乐园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值