HNUCM-2022年秋季学期《算法分析与设计》练习9

目录

问题 A: 牛牛的字符串

问题 B: 滚球游戏

问题 C: 数字三角形之动态规划法

问题 D: 绿地装饰

 问题 E: 解密

问题 F: 整数划分问题之备忘录法

问题 G: 和费马开个玩笑

问题 H: 大还是小?


问题 A: 牛牛的字符串

题目描述:

牛牛有两个字符串(可能包含空格),他想找出其中最长的公共连续子串的长度,希望你能帮助他。例如:两个字符串分别为"abede"和"abgde",结果为2。

输入:

每组数据包括两行,每行为一个字符串。

输出:

输出最长的公共连续子串的长度。

思路:最长连续公共子序列的模板题,maze[i][j]表示str1[i - 1]等于str2[j - 1]时公共连续字串的长度,res用来记录最大值。

while True:
    try:
        str1, str2 = input(), input()
        len1, len2, maze, res = len(str1), len(str2), [], 0
        for _ in range(len1 + 1):
            maze.append([0] * (len2 + 1))
        # print(maze)
        for i in range(1, len1 + 1):
            for j in range(1, len2 + 1):
                if str1[i - 1] == str2[j - 1]:
                    maze[i][j] = maze[i - 1][j - 1] + 1
                    res = max(maze[i][j], res)
                else:
                    maze[i][j] = 0
        # print(maze)
        print(res)
    except:
        break

问题 B: 滚球游戏

题目描述:

某滚球游戏规则如下:球从入口处(第一层)开始向下滚动,每次可向下滚动一层,直到滚至最下面一层为止。球每次可滚至左下、下方或右下三个方格中的任意一个,每个方格都有一个得分,如样例所示。第1层有1个方格,第2层有3个方格,……,以此类推,第n层有2*n-1个方格。设计一个算法,使得球从入口滚至最下面一层的总得分和最大。

输入:

对于每个样例,第1行的正整数n表示数字三角形的行数。(n<=100)
接下来n行包含一个数字三角形,每一行包含2*n-1个方格,对应有2*n-1个表示得分的正整数(不超过10^5),每两个数字之间用空格隔开。
每两组样例之间有一个空行。

输出:

球从入口(第一层)滚至最下面一层的最大得分和。

思路:从最底层往上迭代,这样最顶层maze[0][0]就是我们的目标值,这道题需要注意一下的就是吸收输入中的空行,这里用flag标记到底是空行还是退出。

flag = 0
while True:
    try:
        n, maze, flag = int(input()), [], 1
        for _ in range(n):
            maze.append([int(i) for i in input().split()])
        # print(maze)
        for i in range(n - 2, -1, -1):
            for j in range(2 * (i + 1) - 1):
                maze[i][j] += max(maze[i + 1][j:j + 3])
        print(maze[0][0])
    except:
        if flag == 1:
            flag = 0
        else:
            break

问题 C: 数字三角形之动态规划法

题目描述:

如下图所示的数字三角形,从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。编写一个程序求出最佳路径上的数字之和。 【使用动态规划法实现】

 

         7

       3   8

     8   1   2

   2   7   4   4

4    5   2   6   5

输入:

多组样例输入,每组第一行输入三角形的层数n,接下来n行输入三角形。

输出:

输出最佳路径上的数字之和。

思路:从最底层往上迭代,这样最顶层maze[0][0]就是我们的目标值。

while True:
    try:
        n, maze = int(input()), []
        for _ in range(n):
            maze.append([int(i) for i in input().split()])
        for i in range(n - 2, -1, -1):
            for j in range(i + 1):
                maze[i][j] += max(maze[i + 1][j], maze[i + 1][j + 1])
        print(maze[0][0])
    except:
        break

问题 D: 绿地装饰

题目描述:

湖南中医药大学坐落于中国历史文化名城长沙,是湖南省重点建设本科院校,是全国首批设立国家级重
点学科的高校,也是首批招收博士研究生、留学生及港澳台学生的中医药院校。学校现有 2 个校区,占
地面积 1393 亩,建筑面积 52 万平方米,主校区依岳麓南坡,临湘江西岸,环境幽雅,风光秀丽,是求
学成才的理想之地。
校园景观设计师小 W 的主要工作就是植被环境的设计维护,他有一个 N×N 的模板图,他创作景观的步
骤如下:
1、将当前的绿地分成 N×N 小块,再按照模板图添加装饰(黑色表示有装饰,白色表示没有);
2、对于每个白色(未被装饰)的地块,递归操作 1,应用模板图,即分成更小的 N×N 块,继续进行装
饰,而黑色(已装饰)的地块则不必操作。

下图是某次装饰过程的示意图。

现在你的任务是求出 K 次递归后的绿地状态。

输入:

单组数据。
第一行两个数 N,K,如题意中的描述。
接下来是一个 N×N 的模板图,’ . ’ 表示白色,’ * ’ 表示黑色。
2 ≤ n ≤ 3
1 ≤ k ≤ 5

输出:

输出一个 N K×N K 的矩阵表示答案,不允许有多余的空行或空格。

思路:先算出迭代K以后的地面到底有多大,然后根据模板进行递归修改即可,注意一下坐标换算。

def draw(x: int, y: int, length: int):
    for i in range(x, x + length):
        for j in range(y, y + length):
            maze[i][j] = '*'


def dfs(x: int, y: int, length: int):
    size = length // n
    if size <= 0:
        return
    for i in range(n):
        for j in range(n):
            if model[i][j] == '*':
                draw(x + i * size, y + j * size, size)
            else:
                dfs(x + i * size, y + j * size, size)
    return


n, k = map(int, input().split())
model = [input().strip() for _ in range(n)]
maze = [['.'] * (n ** k) for _ in range(n ** k)]
dfs(0, 0, n ** k)
for m in maze:
    print("".join(m))

 问题 E: 解密

题目描述:

湖南中医药大学有含浦、东塘 2 个校区,学校办学历史悠久,前身为 1934 年的湖南国医专科学校,1953
年创办湖南中医进修学校,1960 年创建普通高等本科院校——湖南中医学院,1979 年成为全国首批取得
中医类研究生学历教育资格的院校,1990 年原湖南科技大学成建制并入湖南中医学院,2002 年与湖南省
中医药研究院合并,2006 年经教育部批准更名为湖南中医药大学,2012 年进入湖南省一本招生序列。
目前,学校与湖南省中医药研究院实行校院合一的管理体制。学校学科门类齐全、中医药特色鲜明。学校
设有 18 个学院、24 个本科专业,涵盖医、理、工、管、文等 5 大学科门类。中医诊断学在本学科研究领
域居国内领先水平。
小 F 居住在含浦校区,他想和东塘校区的同学小 L 聊天,为了保证沟通安全,他发明了一种加密方式,这
种加密方式是这样的:对于一个 01 串,小 F 会将其从左到右每 8 位分成一组,最后一组可能不足 8 位,
对每组进行逆序操作,即如果原来是 bLbL+1bL+2 · · · bR−1bR, 逆序之后变成 bRbR−1bR−2 · · · bL−1bL。现在
小 F 已经加密好了一个串,并且将其发给了小 L,你能帮助小 L 得到这串密文对应的原始信息吗?

输入:

单组数据。
一行一个 01 串,代表加密后的字符串,串长度大于 0, 小于等于 100。

输出:

一行字符串,代表加密后的字符串所对应的原始信。

思路:模拟,每8位一翻转,注意一下一组不足8位的情况。

while True:
    try:
        strings = input().strip()
        res, temp, cnt = "", "", 0
        for s in strings:
            res, cnt = s + res, cnt + 1
            if cnt >= 8:
                temp, cnt, res = f"{temp + res}", 0, ""
        # print(cnt)
        print(temp + res)
    except:
        break

问题 F: 整数划分问题之备忘录法

题目描述:

使用备忘录法编写一个程序,求一个正整数n的所有划分个数。 
例如,输入3,输出3;输入4,输出5。 

输入:

多组输入,每一组是一个正整数n。

输出:

输出划分数。

思路:利用二维列表存储数据,自底向上计算,maze[n][m]表示整数n的加数最大不超过m的划分数 。

maze = [[1]]
while True:
    try:
        nums = int(input())
        if nums >= len(maze):
            for i1 in range(len(maze), nums + 1):
                for j1 in range(i1 + 1):
                    if j1 == 0:
                        maze.append([0] * (i1 + 1))
                    else:
                        maze[i1][j1] = maze[i1][j1 - 1] + maze[i1 - j1][min(i1 - j1, j1)]
        print(maze[nums][nums])
    except:
        break

问题 G: 和费马开个玩笑

题目描述: 

费马大定理:当n>2时,不定方程an+bn=cn没有正整数解。比如a3+b3=c3没有正整数解。我们来给他开个玩笑:把方程改成a3+b3=c3,这样就有解了,比如a=4, b=9, c=79时43+93=793。
输入两个整数x, y, 求满足x<=a,b,c<=y的整数解的个数。

输入:

输入最多包含10组数据。每组数据包含两个整数x, y(1<=x,y<=108)。

输出:

对于每组数据,输出解的个数。

思路:双重循环判断,注意结束条件。

cnt = 0
while True:
    try:
        x, y = map(int, input().split())
        res, cnt = 0, cnt + 1
        for a in range(x, min(y + 1, 1001)):
            for b in range(x, a + 1):
                n = a ** 3 + b ** 3
                if n % 10 == 3 and x <= n // 10 <= y:
                    # print(a, b, n)
                    res = res + 2 if a != b else res + 1
        print(f"Case {cnt}: {res}")
    except:
        break

问题 H: 大还是小?

题目描述:

输入两个实数,判断第一个数大,第二个数大还是一样大。每个数的格式为:

[整数部分].[小数部分] 

简单起见,整数部分和小数部分都保证非空,且整数部分不会有前导 0。不过,小数部分的最 后可以有 0,因此 0.0和 0.000是一样大的。 

输入:

输入包含不超过 20组数据。每组数据包含一行,有两个实数(格式如前所述)。每个实数都 包含不超过 100个字符。 

输出:

对于每组数据,如果第一个数大,输出"Bigger"。如果第一个数小,输出"Smaller"。如果两个 数相同,输出"Same"。 

思路:因为整数部分没有前导0,所以可以通过判断整数部分的长度初步判断大小。如果长度相等再判断整数的数值大小,还相等的话,再将小数部分对齐补0,判断大小。

def init():
    global df1, df2
    if length3 < length4:
        df1 = df1 + "0" * (length4 - length3)
    else:
        df2 = df2 + "0" * (length3 - length4)
 
 
def check(str1: str, str2: str, n: int):
    for i in range(n):
        if str1[i] < str2[i]:
            return -1
        if str1[i] > str2[i]:
            return 1
    return 0
 
 
cnt = 0
while True:
    try:
        string1, string2 = input().split()
        i1, df1 = string1.split('.')
        i2, df2 = string2.split('.')
        length1, length2, length3, length4 = len(i1), len(i2), len(df1), len(df2)
        init()
        k, ctl = check(i1, i2, length1), check(df1, df2, max(length3, length4))
        # print(1)
        if length1 < length2 or k == -1 or (k == 0 and ctl == -1):
            res = "Smaller"
        elif length1 > length2 or k == 1 or (k == 0 and ctl == 1):
            res = "Bigger"
        else:
            res = "Same"
        cnt += 1
        print(f"Case {cnt}: {res}")
    except:
        break
好的,我可以为您讲解一下 HNUCM 最小生成树(Prim)的算法过程。 首先,Prim 算法是一种贪心算法,用于求解带权无向连通图的最小生成树。下面是具体的算法过程: 1. 选取任意一个顶点作为起点,将其加入到生成树中。 2. 找到与已经加入到生成树中的顶点相邻的所有顶点,并计算它们与生成树的距离。 3. 从这些顶点中选取距离最小的顶点,将其加入到生成树中。 4. 重复步骤2和3,直到生成树中包含了所有的顶点。 在具体实现时,可以使用一个数组来记录每个顶点是否已经加入到生成树中,以及另一个数组来记录每个顶点与生成树的距离。每次选择距离最小的顶点时,可以使用一个最小堆来优化。 至于 HNUCM 最小生成树 Prim 算法的具体实现,可以参考以下代码: ```python import heapq def prim(graph): n = len(graph) visited = [False] * n distance = [float('inf')] * n distance[0] = 0 heap = [(0, 0)] result = 0 while heap: (d, u) = heapq.heappop(heap) if visited[u]: continue visited[u] = True result += d for v, weight in graph[u]: if not visited[v] and weight < distance[v]: distance[v] = weight heapq.heappush(heap, (weight, v)) return result ``` 这段代码实现了 HNUCM 最小生成树 Prim 算法的过程,其中 graph 是一个邻接表表示的带权无向连通图,每个元素是一个二元组 (v, w),表示从节点 u 到节点 v 有一条边权为 w 的边。算法的返回值是最小生成树的总权值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值