2024年春季学期《算法分析与设计》练习9

问题 A: 斜线最大最小值

题目描述

求如图所示一个上三角矩阵中每一条斜线中的最大元素(L)和最小元素(S)。

输入

每组输入包括两部分,一部分为数字n,表示三角矩阵的行数。
第二部分即为三角矩阵。

输出

每一个对角线输出一行,每行包括Lx=Max, Sx=Min,其中x为斜线序号(序号从1开始),Max为该斜线上的最大值,Min为该斜线上的最小值。

样例输入 Copy
6
1 3 5 7 11 20
0 6 8 2 3 13
0 0 7 4 8 9
0 0 0 18 3 10
0 0 0 0 12 6
0 0 0 0 0 15
样例输出 Copy
L1=18, S1=1
L2=8, S2=3
L3=10, S3=2
L4=9, S4=3
L5=13, S5=11
L6=20, S6=20
# Python版本  

# 初始化变量  
the_max = None
the_min = None


def read_matrix():
    n = int(input())
    matrix = [[0 for _ in range(n)] for _ in range(n)]
    for i in range(n):
        row = list(map(int,input().split()))
        matrix[i] = row
    return matrix, n


def find_max_min_diagonals(matrix, n):
    for r in range(1, n + 1):
        # 初始化最大和最小值为当前对角线的第一个元素  
        the_max = matrix[0][r - 1]
        the_min = matrix[0][r - 1]

        # 遍历对角线  
        for i in range(1, n - r + 1):
            j = i + r - 1
            # 更新最大值和最小值  
            the_max = max(the_max, matrix[i][j])
            the_min = min(the_min, matrix[i][j])

            # 打印结果
        print("L{}={}, S{}={}".format(r, the_max, r, the_min))

    # 主程序


while True:
    try:
        matrix, n = read_matrix()
        find_max_min_diagonals(matrix, n)
    except EOFError:
        break

问题 B: 矩阵连乘问题-备忘录法求最优值

题目描述

使用备忘录法求解矩阵连乘问题,输出最少乘法次数。

输入

每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。

输出

矩阵连乘最优计算次数。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
15125
def matrix_chain_order(p):
    n = len(p) - 1  # 矩阵数量  
    m = [[0] * n for _ in range(n)]  # 初始化备忘录数组  

    for chain_length in range(2, n + 1):  # 链的长度从2开始递增  
        for i in range(0, n - chain_length + 1):
            j = i + chain_length - 1
            m[i][j] = float('inf')  # 初始化为无穷大  
            for k in range(i, j):
                q = m[i][k] + m[k + 1][j] + p[i] * p[k + 1] * p[j + 1]
                if q < m[i][j]:
                    m[i][j] = q

    return m[0][n - 1]  # 返回最优解  


while 1:
    n = int(input())
    p = list(map(int, input().split()))

# 输出最少乘法次数  
    print(matrix_chain_order(p))

问题 C: 矩阵连乘问题-动态规划求最优值

题目描述

使用动态规划算法求解矩阵连乘问题,输出最少乘法次数。

输入

每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。

输出

矩阵连乘最优计算次数。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
15125
def matrix_chain_order(p):
    n = len(p) - 1  # 矩阵数量
    m = [[0] * n for _ in range(n)]  # 最少乘法次数数组
    s = [[0] * n for _ in range(n)]  # 存储分割点数组(可选,用于重构最优解)

    # 初始化对角线上的值为0,因为单个矩阵不需要乘法操作
    for i in range(n):
        m[i][i] = 0

        # 动态规划填充 m 和 s 数组
    for chain_length in range(2, n + 1):  # 链的长度从2开始递增
        for i in range(0, n - chain_length + 1):
            j = i + chain_length - 1
            m[i][j] = float('inf')  # 初始化为无穷大
            for k in range(i, j):
                q = m[i][k] + m[k + 1][j] + p[i] * p[k + 1] * p[j + 1]
                if q < m[i][j]:
                    m[i][j] = q
                    s[i][j] = k  # 记录最优分割点

    # 返回最少乘法次数
    return m[0][n - 1]


while 1: 
    n = int(input())
    p = list(map(int, input().split()))

    # 输出最少乘法次数
    print(matrix_chain_order(p))

问题 D: 矩阵连乘问题-构造最优解

题目描述

使用动态规划算法求解矩阵连乘问题。

输入

每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。

输出

矩阵连乘最优计算次序。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
A[2:2] * A[3:3]
A[1:1] * A[2:3]
A[4:4] * A[5:5]
A[4:5] * A[6:6]
A[1:3] * A[4:6]
def f(sz, i, j):
    if i == j:
        return
    f(sz, i, sz[i][j])
    f(sz, sz[i][j] + 1, j)
    res.append('A[' + str(i) + ':' + str(sz[i][j]) + ']' + ' * ' + 'A[' + str(sz[i][j] + 1) + ':' + str(j) + ']')


while True:
    n = int(input())
    res = []
    arr = list(map(int, input().split()))
    dp = [[0] * n for _ in range(n + 1)]
    sz = [[0] * n for _ in range(n + 1)]
    for r in range(2, n + 1):
        for i in range(1, n + 1 - r):
            j = i + r - 1
            dp[i][j] = dp[i + 1][j] + arr[i - 1] * arr[i] * arr[j]
            sz[i][j] = i
            for k in range(i + 1, j):
                t = dp[i][k] + dp[k + 1][j] + arr[i - 1] * arr[k] * arr[j]
                if t < dp[i][j]:
                    dp[i][j] = t
                    sz[i][j] = k
    f(sz, 1, n - 1)
    for i in range(len(res)):
        print(res[i])

问题 E: 石子合并问题

题目描述

在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。例如:输入{1,2,3,4,5},输出33。【3+6+9+15=33】

输入

本题应该处理到文件尾,每组输入包括两行,第一行为石子堆的个数n,第二行则为每堆石子的个数。

输出

输出最小花费。

样例输入 Copy
5
1 2 3 4 5
样例输出 Copy
33
import math
def min_cost_partition(n, arr):
    dp = [[0] * (n + 1) for _ in range(n + 1)]
    exp = [[0] * (n + 1) for _ in range(n + 1)]
    for i in range(1, n + 1):
        exp[i][i] = arr[i - 1]
    for i in range(1, n):
        for j in range(i + 1, n + 1):
            exp[i][j] = exp[i][j - 1] + arr[j - 1]
    for r in range(2, n + 1):
        for i in range(1, n + 2 - r):
            j = i + r - 1
            dp[i][j] = math.inf
            for k in range(i, j):
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j])
            dp[i][j] += exp[i][j]
    return dp[1][-1]

while 1:
    n = int(input())
    arr = list(map(int, input().split()))
    print(min_cost_partition(n, arr))

问题 F: X星人的基因

题目描述

X星人的基因由A、B、C、D、E五种不同的结构组合而成。
如果两个性别不同的X星人的基因序列相似度大于50%,按照X星的法律他们是禁止结婚的,等于50%据说还是可以的。
那么基因的相似度怎么计算呢?分别从两个人身上取长度均为N的基因片段,如果它们的最长公共子序列为M,则相似度=M/N。是不是很简单呢?
现在给你两段X星人的基因序列片段,请你判断他们是不是可以结婚?

输入

每一组测试数据包含3行,
第1行数字N表示待比较基因序列片段的长度,N<=10^3。
第2行和第3行为两个长度为N的基因序列片段。
输入0表示结束。

输出

两个X星人是否可以结婚,如果可以输出”Yes“,如果不可以输出”No“。

样例输入 Copy
8
A B C D E A B C
A C C D C B A E
6
A B C D E E
A E D C B B
0
样例输出 Copy
Yes
Yes
while True:
    n = int(input())
    if n == 0:
        break

    s1 = ''.join(list(map(str, input().split())))
    s2 = ''.join(list(map(str, input().split())))

    m = len(s1)
    n = len(s2)

    # 初始化动态规划数组
    dp = [[0] * (n + 1) for _ in range(m + 1)]

    # 填充动态规划数组
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if s1[i - 1] == s2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

                # 获取最长公共子序列的长度
    res = dp[m][n]

    # 判断最长公共子序列长度是否超过字符串长度的一半
    if res > m * (1 / 2):  # 注意这里应该使用 m 而不是 n,因为我们需要比较的是 s1 长度的一半
        print('No')
    else:
        print('Yes')

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值