Python练习题最长路径问题(字典)

目录

原题目

题目翻译

题目给出的模板

题目分析

解答过程

测试输出

完整代码

quiz.py

test.py

 


昨天有一个留学生朋友问了我一到python题,题目如下:

原题目

Besides a function to generate a random dictionary,defines two functions that analyse a dictionary.See the pdf for explanations via an illustrationand examples of possible uses.
You can assume that both functions are called with proper arguments (namely, a dictionary whose keys are all integers between 1 and n for some strictly positive integer n and whose values are numbers between 1 and n,and an integer between 1 and n).
The lines that are output by the function longest_strictly_decreasing_sequences_to() are ordered from smallest first value to largest first value.

题目翻译

除了生成随机字典的函数外,还定义了两个分析字典的函数。请参阅 pdf 以通过插图和可能使用的示例进行解释。
您可以假设这两个函数都使用适当的参数调用(即,对于某些严格的正整数 n,其键都是 1 和 n 之间的整数,其值是 1 和 n 之间的数字,以及 1 和 n 之间的整数)。
#函数longest_strictly_decreasing_sequences_to() 输出的行从最小的第一个值到最大的第一个值排序。

题目给出的模板

from random import seed, randint

def generate_mapping(for_seed, length):
    seed(for_seed)
    return {i: randint(1, length) for i in range(1, length + 1)}

def follow_the_arrows_from(mapping, n):
    pass
    # REPLACE PASS ABOVE WITH YOUR CODE

def longest_strictly_decreasing_sequences_to(mapping, n):
    if n not in mapping.values():
        return

题目分析

需要实现两个函数

def follow_the_arrows_from(mapping, n):
...
def longest_strictly_decreasing_sequences_to(mapping, n):
...

第一个函数是用种子生成一个字典

mapping = generate_mapping(30, 12)

打印结果如下

{1: 9, 2: 5, 3: 10, 4: 1, 5: 10, 6: 11, 7: 4, 8: 5, 9: 1, 10: 7, 11: 7, 12: 11}

 根据生成的mapping运行第二个函数:

输出的语句里可以理解为:第一句是陷入循环需要几步,第二句是循环有多长。


第三个函数实现,输入n,输出最长路径,如上面的字典,输入1其对应的键有4和9;4作为值对应的键有7,9作为值对应的键有1,1小于9,到头第二条路经是9 ->1;7作为值对应的键有10和11,10作为值对应的键有5,5小于10到头,路径10->7->1,11作为值对应的键为12,到头,路径12 -> 11 -> 7 -> 4 -> 1,输出这条最长路径。

解答过程

这里我认为可以用列表储存每次路过的值然后判断是否循环,代码如下:

def follow_the_arrows_from(mapping, n):
    li = [n]
    temp = n
    while True:
        n = mapping[n]
        if n not in li:
            li.append(n)
        else:
            if n == temp:
                print(f'It is on a loop of length {len(li)}')
                break
            else:
                print(f'It starts with a stalk of length {li.index(n)}')
                print(f'It reaches {n} on a loop of length {len(li) - li.index(n)}')
                break

第一个比较简单,下面看第二个,完整代码

#函数longest_strictly_decreasing_sequences_to() 输出的行从最小的第一个值到最大的第一个值排序。
def longest_strictly_decreasing_sequences_to(mapping, n):
    if n not in mapping.values():
        return
    lis = []
    # lis_end = []
    for i in range(len(mapping), 0, -1):  # 倒序循环
        li = []
        # path_num = mapping[i]
        while n <= mapping[i] < i:  # 判断该键对应的值是否小于键,且大于或等于n
            li.append(i)  # 满足条件加入列表
            i = mapping[i]  #将该值作为新键进行下一轮判断
        # 当结束上一循环获得一个列表时进入下一个判断
        if len(li) != 0 and i == n:  # 如果这个列表非空,且最后的值等于n,满足条件
            li += [n]  # 将n加入列表
            lis.append(li)  # 将li加入满足条件最终值为n的列表集
    for li in lis:
        if len(li) == len(max(lis)):  # 最长路径可能有多个,判断是不是最长路径
            s1 = ' -> '.join(str(n) for n in sorted(li, reverse=True))
            print(s1)  # 输出最长路径

这个方法是倒着遍历字典,然后判断最终指向的值是不是n,如果是n就保存到列表里,把所有符合的列表保存到二位列表,最后判断最长的几个输出。

测试输出

mapping = generate_mapping(30, 12)
print(mapping)
follow_the_arrows_from(mapping, 6)
follow_the_arrows_from(mapping, 4)
longest_strictly_decreasing_sequences_to(mapping, 1)
longest_strictly_decreasing_sequences_to(mapping, 7)

 输出结果:

{1: 9, 2: 5, 3: 10, 4: 1, 5: 10, 6: 11, 7: 4, 8: 5, 9: 1, 10: 7, 11: 7, 12: 11}
It starts with a stalk of length 4
It reaches 1 on a loop of length 2
It starts with a stalk of length 1
It reaches 1 on a loop of length 2
12 -> 11 -> 7 -> 4 -> 1
12 -> 11 -> 7

不过,题目下方还给出了一个提示:

# Hint: create a dictionary, D, whose keys are the
# numbers i in the interval [n + 1, len(mapping)]
# such that there is a path from i to n, with as
# corresponding value the length of this path.
# max(D.values()) evaluates to the largest length
# of those paths; let M denote that value.
# For each number i in the interval [n + 1, len(mapping)],
# if i is a key of D and M is the associated value, then
# output i, mapping[i], mapping[mapping[i]], ..., n,
# separating consecutive values with ->.
# INSERT YOUR CODE HERE

提示:创建一个字典 D,其键是区间 [n + 1, len(mapping)] 中的数字 i,使得存在从 i 到 n 的路径,对应的值是该路径的长度。 max(D.values()) 计算这些路径的最大长度;让 M 表示该值。对于区间 [n + 1, len(mapping)] 中的每个数 i,如果 i 是 D 的键,M 是关联值,则输出 i, mapping[i], mapping[mapping[i]], . .., n, 用 -> 分隔连续值。

 感觉略麻烦,没有试,有兴趣的朋友可以试一下。

完整代码

quiz.py

from random import seed, randint


def generate_mapping(for_seed, length):
    seed(for_seed)
    return {i: randint(1, length) for i in range(1, length + 1)}


def follow_the_arrows_from(mapping, n):
    li = [n]
    temp = n
    while True:
        n = mapping[n]
        if n not in li:
            li.append(n)
        else:
            if n == temp:
                print(f'It is on a loop of length {len(li)}')
                break
            else:
                print(f'It starts with a stalk of length {li.index(n)}')
                print(f'It reaches {n} on a loop of length {len(li) - li.index(n)}')
                break

    # REPLACE PASS ABOVE WITH YOUR CODE


def longest_strictly_decreasing_sequences_to(mapping, n):
    if n not in mapping.values():
        return
    lis = []
    # lis_end = []
    for i in range(len(mapping), 0, -1):  # 倒序循环
        li = []
        # path_num = mapping[i]
        while n <= mapping[i] < i:  # 判断该键对应的值是否小于键,且大于或等于n
            li.append(i)  # 满足条件加入列表
            i = mapping[i]  #将该值作为新键进行下一轮判断
        # 当结束上一循环获得一个列表时进入下一个判断
        if len(li) != 0 and i == n:  # 如果这个列表非空,且最后的值等于n,满足条件
            li += [n]  # 将n加入列表
            lis.append(li)  # 将li加入满足条件最终值为n的列表集
    for li in lis:
        if len(li) == len(max(lis)):  # 最长路径可能有多个,判断是不是最长路径
            s1 = ' -> '.join(str(n) for n in sorted(li, reverse=True))
            print(s1)  # 输出最长路径

test.py

from quiz import *
mapping = generate_mapping(30, 12)
print(mapping)
follow_the_arrows_from(mapping, 6)
follow_the_arrows_from(mapping, 4)
longest_strictly_decreasing_sequences_to(mapping, 1)
longest_strictly_decreasing_sequences_to(mapping, 7)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值