HNUCM-蓝桥杯PythonB组寒假练习2

问题 A: 选房子

题目描述

栋栋和李剑已经大四了,想要出去找房子住。他们一共看中了n套房子。其中第i套房子已经住了ai个人了,它最多能住bi个人。栋栋和李剑想要住在一起,那么请问他们有几套可以选择的房子?

输入

输入的第一行为一个正整数T (T<=1000),代表一共有T组测试数据。

每组测试数据的第一行有一个正整数n (1<=n<=100),代表一共有n套房子。接下来n行,每行有两个正整数ai,bi (1<=ai<=bi<=100),分别代表现在已经住了ai个人和最多能住bi个人。

输出

对于每组测试数据,输出一行包含一个整数,代表他们可以选择房子的数量。

思路

简单的减法判断题,判断b - a 是否大于2即可。

代码

t = int(input())
while t > 0:
    t, n, cnt = t - 1, int(input()), 0
    for _ in range(n):
        a, b = map(int, input().split())
        if b - a >= 2:
            cnt += 1
    print(cnt)

问题 B: 倍数问题

题目描述

众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。

但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。

现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数

使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

输入

第一行包括 2 个正整数 n, K。

第二行 n 个正整数,代表给定的 n 个数。

1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。

输出

输出一行一个整数代表所求的和。

思路

题目可以使用枚举也可以使用动态规划(0-1背包)的思路进行解题,以下为枚举法。因为题目要求选取三个数,通过推理我们不难发现,在某一余数情况下,最多选取三个数,最少选取零个数。同时为了满足“最大"的要求,可以使用一个二维列表结合插入排序对输入进行处理,每个余数情况下,至多保留三个最大的数,以此降低题目规模。然后枚举三个数的余数,确定这三个数。

代码

while True:
    try:
        n, k = map(int, input().split())
        # remainder二维列表用来存储处理余数后的输入,res存储结果
        remainder, nums, res = [[0] * 3 for i in range(k)], list(map(int, input().split())), 0
        for num in nums:  # 使用插入排序,保证每个余数列表remainder[i]不会超过三个数,且存储的数为最大的三个数
            re = num % k  # 获取余数
            if num > remainder[re][0]:  # 插入排序
                remainder[re][0], remainder[re][1], remainder[re][2] = num, remainder[re][0], remainder[re][1]
            elif num > remainder[re][1]:
                remainder[re][1], remainder[re][2] = num, remainder[re][1]
            elif num > remainder[re][2]:
                remainder[re][2] = num
        # 枚举余数,获得三个数,三个数分别为a, b, c
        for i in range(k):  # i代表a的余数
            for j in range(i, k):  # j代表b的余数
                z = (k - i + k - j) % k  # z代表c的余数
                a = remainder[i][0]  # 根据a的余数获得a
                if i == j:  # 如果a的余数和b的余数相同
                    b = remainder[i][1]  # 根据b的余数获得b
                    c = remainder[i][2] if i == z else remainder[z][0]  # 根据c的余数获得c
                else:  # 如果a的余数和b的余数不同
                    b = remainder[j][0]  # 根据b的余数获得b
                    c = remainder[i][1] if i == z else remainder[j][1] if j == z else remainder[z][0]  # 根据c的余数获得c
                if a + b + c > res:  # 比较,获得结果
                    res = a + b + c
        print(res)  # 输出结果
    except:
        break

问题 C: X星游戏

题目描述

X星人这几天很无聊,他发明了一个自娱自乐的小游戏。

现在有若干张写有0、1、2、3、......、9这10个数字之一的纸牌,每一次可以拿出一张牌。

将抽取到的牌中的数字连成一个数列,如果当前抽的牌中的数字在前面出现过,则收取这两张牌及其它们之间所有的牌。

请你编写一个程序,计算最多的一次可以收取到多少张牌?

【注:可能最后还留有一些牌没有被收取】

输入

单组输入。

第1行输入一个数字N,表示X星人总共抽取的牌数,N<=1000。

第2行输入N个数字,分别对应X星人每一次抽取到的纸牌上的数字,两两之间用空格隔开。

输出

输出最多一次可以收取到的牌的数量。

思路

简单的模拟题,模拟游戏的操作,对列表进行删除即可。

代码

def add(x: int, y: int):
    global res, index
    res = max(res, y - x + 1)
    for i in range(y, x - 1, -1):
        del nums[i]
    index = x


n, nums, index, res = int(input()), [int(i) for i in input().split()], 1, -1
while True:
    try:
        tmp = nums[index]
        if tmp in nums[:index]:
            add(nums[:index].index(tmp), index)
        else:
            index += 1
    except:
        break
print(res)

问题 D: 近似回文词

题目描述

输入一行文本,输出最长近似回文词连续子串。所谓近似回文词是指满足以下条件的字符串:

1. S以字母开头,字母结尾

2. a(S)和b(S)最多有2k个位置不同,其中a(S)是S删除所有非字母字符之后得到的串,b(S)是a(S)的逆序串。

比如当k=1时,Race cat是一个近似回文词,因为a(S)=racecat和b(S)=tacecar只有2个位置不同。

输入

输入包含不超过25组数据,每组数据包含两行。第一行是整数k(0<=k<=200),第二行为字符串S,包含不超过1000个字符(换行符不算)。S只包含字符、空格和其他可打印字符(比如逗号,句号),并且不会以空白字符开头。

输出

对于每组测试数据,输出最长近似回文子串的长度和起始位置(S的第一个字符是位置1)。如果有多个最长近似回文子串解,起始位置应尽量小。

思路

利用其他的列表存储源字符串的字母与下标信息,对字符串的字母进行回文串的判断(枚举中间位,分奇数与偶数两种长度情况)。

代码

cnt = 0
while True:
    try:
        cnt, k, buf = cnt + 1, int(input()), list(input().lower())
        n, p, ch, res = len(buf), [], [], -1
        # print(buf)
        for i in range(n):
            if buf[i].isalpha():
                p.append(i + 1), ch.append(buf[i])
        # print(buf, p, ch)
        f, n = 0, len(p)
        for i in range(n):
            err, j = k, 0
            while i - j >= 0 and i + j < n:
                if ch[i - j] != ch[i + j]:
                    err -= 1
                    if err < 0:
                        break
                t = p[i + j] - p[i - j] + 1
                if t > res:
                    res, f = t, p[i - j]
                j += 1
            err, j = k, 0
            while i - j >= 0 and i + j + 1 < n:
                if ch[i - j] != ch[i + j + 1]:
                    err -= 1
                    if err < 0:
                        break
                t = p[i + j + 1] - p[i - j] + 1
                if t > res:
                    res, f = t, p[i - j]
                j += 1
        print(f"Case {cnt}: {res} {f}")
    except:
        break

E: 最少硬币

题目描述

假设有4种硬币,它们的面值分别为1分、5分、10分和25分。

现在要找给顾客n分钱。

请问怎样找零钱才能使给顾客的硬币个数最少?

输出所需最少硬币的枚数。

输入

输入需要找给顾客的零钱n(单位:分)。

输出

输出所需最少硬币的枚数。

思路

经典的贪心问题,从最大的硬币开始找即可。

代码

money = [25, 10, 5, 1]
while True:
    try:
        n, cnt, index = int(input()), 0, 0
        while n > 0:
            if n >= money[index]:
                n, cnt = n % money[index], cnt + n // money[index]
            else:
                index += 1
        print(cnt)
    except:
        break

F: X星大学

题目描述

X星大学新校区终于建成啦!

新校区一共有N栋教学楼和办公楼。现在需要用光纤把这N栋连接起来,保证任意两栋楼之间都有一条有线网络通讯链路。

已知任意两栋楼之间的直线距离(单位:千米)。为了降低成本,要求两栋楼之间都用直线光纤连接。

光纤的单位成本C已知(单位:X星币/千米),请问最少需要多少X星币才能保证任意两栋楼之间都有光纤直接或者间接相连?

注意:如果1号楼和2号楼相连,2号楼和3号楼相连,则1号楼和3号楼间接相连。

输入

单组输入。

第1行输入两个正整数N和C,分别表示楼栋的数量和光纤的单位成本(单位:X星币/千米),N<=100,C<=100。两者之间用英文空格隔开。

接下来N*(N-1)/2行,每行包含三个正整数,第1个正整数和第2个正整数表示楼栋的编号(从1开始一直到N),编号小的在前,编号大的在后,第3个正整数为两栋楼之间的直线距离(单位:千米)。

输出

输出最少需要多少X星币才能保证任意两栋楼之间都有光纤直接或者间接相连。

思路

最短路径问题,可以采用对应的算法即可。

代码

N, C = map(int, input().strip().split(' '))
v = set()
load = []
cost = 0
uuu = N * (N - 1) // 2
while uuu > 0:
    uuu -= 1
    a, b, c = map(int, input().strip().split(' '))
    load.append((c, a, b))
load.sort()
# print(loads)
c, a, b = load.pop(0)
v.add(a)
v.add(b)
cost += c
while len(v) < N:
    for c, a, b in load:
        if (a in v and b not in v) or (a not in v and b in v):
            v.add(a)
            v.add(b)
            cost += c
            break
        # print(11)
# print(v)
print(cost * C)

G: 奖牌榜

题目描述

X星学校的运动会正在激烈进行中。

现在需要请你编写一个程序来显示所有班级的奖牌榜,显示规则如下:

(1) 优先按照金牌数量降序排列后显示。

(2) 如果金牌数相等则比较银牌数,银牌数多者显示在前。

(3) 如果金牌和银牌数都相等,则比较铜牌数,铜牌数多者显示在前。

(4) 如果金、银、铜数量均相等,则按照班级编号从小到大排列后显示。

(5) 需要按照班级编号、金牌数、银牌数、铜牌数、奖牌总数的顺序显示每个班级的奖牌情况。

已知X星学校的班级编号为一个四位正整数,且班级编号具有唯一性。

输入

单组输入。

第1行输入一个正整数N,表示班级的总数量,N<=9000。

接下来N行,每1行包含四个正整数,分别表示班级编号、金牌数、银牌数和铜牌数。金牌数、银牌数和铜牌数均小于100。两两之间用英文空格隔开。

输出

显示按照规则排序之后的奖牌榜,每一行都包含班级编号、金牌数、银牌数、铜牌数和奖牌总数,两两之间用英文空格隔开。

思路

使用sort函数结合lambda函数即可完成解题。

代码

n, t, box = int(input()), 0, []
while t < n:
    t += 1
    a, b, c, d = map(int, input().split())
    box.append((a, b, c, d))
box.sort(key=lambda x: [-x[1], -x[2], -x[3], x[0]])
for a, b, c, d in box:
    print(a, b, c, d, b + c + d)

你可能感兴趣的:(算法分析与设计,算法,python,动态规划,贪心算法)