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

问题 A: 菱形图案

题目描述

KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的菱形图案。

输入

多组输入,一个整数(2~20)。

输出

针对每行输入,输出用“*”组成的菱形,每个“*”后面有一个空格。每输出一个菱形的后面需要空一行。

样例输入 Copy
2
3
4
样例输出 Copy
  * 
 * * 
* * * 
 * * 
  * 

   * 
  * * 
 * * * 
* * * * 
 * * * 
  * * 
   * 

    * 
   * * 
  * * * 
 * * * * 
* * * * * 
 * * * * 
  * * * 
   * * 
    * 
while True:
    n = int(input())
 
    for i in range(n):
        print(' ' * (n - i) + '* ' * (i + 1))
    print('* ' * (n+1))
    for i in range(n):
        print(' ' * (i + 1) + '* ' * (n - i))
    print()

问题 B: X星人的礼物
 

题目描述

六一儿童节到了,X星人宝宝收到了很多很多礼物。他决定把这些礼物装到自己的礼物箱中。为此,他准备了很多个型号相同的礼物箱,每个礼物箱能够装礼物的最大重量都是一样的。但是X星人宝宝不希望在一个礼物箱里面装太多礼物(可能担心礼物会被压坏吧),每个礼物箱最多只允许装2个礼物
假设X星人宝宝收到了N个礼物,现在给出每一个礼物的重量和一个礼物箱的最大装载量,请你编写一个程序计算X星人宝宝最少要用多少个礼物箱才能够把所有的礼物都装完

输入

单组输入。
每组两行,第1行输入两个正整数,分别表示礼物的数量N和每个礼物箱的最大装载量C,其中1<=N<=1000,1<=C<=100,两者之间用英文空格隔开。
第2行输入N个不超过100的正整数,分别表示每一个礼物的重量,两两之间用英文空格隔开。
输入保证最重的礼物的重量<=C。

输出

针对所输出的数据,输出将所有的礼物全部都装完所需的礼物箱的最少个数。

样例输入 Copy
5 80
20 70 40 30 10
样例输出 Copy
3
def count_pairs(arr, c):
    arr.sort()
    count = 0
    left = 0
    right = len(arr) - 1

    # 遍历数组  
    while left < right:
        if arr[left] + arr[right] <= c:
            left += 1 
        right -= 1 
        count += 1
  
    if left == right and left < len(arr):
        count += 1

    return count

while True:
    n, c = map(int, input().split())
    arr = list(map(int, input().split()))
    print(count_pairs(arr, c))

问题 C: 隔离14天

题目描述

      题目涉政

输入
第1行的第1个数字n表示总人数,第2个数字m表示汽车数量;从第2行开始,接下来的m行表示每辆汽车的司乘人员总人数和人员编号(人员编号是一个固定值,可以对应于我们的身份证号码),每一行的第1个数字k表示该汽车的司乘人员总数,接下来的k个数字表示每一个人的编号。
输出
需要被隔离的总人数。
样例输入 Copy
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
样例输出 Copy
4
n, m = map(int, input().split())
a = []  # 存储每辆车的乘客列表
p = []  # 存储已经检查过的车辆索引
q = []  # 存储所有阳性乘客的列表


for i in range(m):
    a.append(list(map(int, input().split()))[1:])


for i in range(m):
    if 0 in a[i]:
        p.append(i)
        q.extend(a[i])


q = list(set(q))


found_new = True
while found_new:
    found_new = False
    for i in range(m):
        if i not in p:
            if any(passenger in q for passenger in a[i]):
                p.append(i)  
                q.extend(a[i])  
                found_new = True  
                break  


unique_q = set(q)

print(len(unique_q))

问题 D: 最小生成树(Kruskal)

题目描述

编程实现Kruskal算法,求图的最小生成树(MST)的权重。

输入

每组数据分为两个部分,第一部分为图的点数n,和边数m, 
第二部分为m行,每一行输入三个数字,前两个为两个顶点的编号,第三个为边权重。 

输出

最小生成树的权重。

样例输入 Copy
3 3
0 1 10
0 2 15
1 2 50
样例输出 Copy
25
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        rootX = self.find(x)
        rootY = self.find(y)
        if rootX != rootY:
            if self.rank[rootX] > self.rank[rootY]:
                self.parent[rootY] = rootX
            elif self.rank[rootX] < self.rank[rootY]:
                self.parent[rootX] = rootY
            else:
                self.parent[rootY] = rootX
                self.rank[rootX] += 1

def kruskal(n, edges):
    edges.sort(key=lambda x: x[2])
    uf = UnionFind(n)
    total_weight = 0
    mst_edges = 0

    for edge in edges:
        u, v, weight = edge
        if uf.find(u) != uf.find(v):
            uf.union(u, v)
            total_weight += weight
            mst_edges += 1
            if mst_edges == n - 1:  # 当MST包含n-1条边时,停止添加边
                break

    return total_weight

n, m = map(int, input().split())
edges = []
for _ in range(m):
    u, v, weight = map(int, input().split())
    edges.append((u, v, weight))

print(kruskal(n, edges))

问题 E: 搭建电路

题目描述

明明迷上了一个搭建电路的游戏。
在游戏中,每次在两个电子元件之间增加一条有效电路(两个元件之间先前没有电路相连)都将获得相应的积分奖励。
已知电子元件数量n和部分电子元件之间的奖励积分值。如何构建一个有效电路将所有元件全部连接起来,并且可以得到最多的积分奖励。

输入

每组输入数据包含m+1行。
第1行输入两个正整数n和m,其中n表示电子元件数量(n<=100),m表示提供了m对电子元件之间的奖励积分值(m<=1000)。两个正整数之间用空格隔开。
第2行到第m+1行对应m对电子元件及其对应的奖励积分值,每一行包含三个正整数,第1个和第2个整数表示电子元件编号(从1开始),第3个整数表示两个元件之间搭建电路的奖励积分num(num<1e9)。整数之间用空格隔开。

输出

每组输出占1行,输出一个正整数,即最多可以得到的积分奖励值。如果没有办法把所有元件全部连接起来,则输出“No solution.”。

样例输入 Copy
3 3
1 2 10
1 3 20
2 3 30
样例输出 Copy
50
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        rootX = self.find(x)
        rootY = self.find(y)
        if rootX != rootY:
            if self.rank[rootX] > self.rank[rootY]:
                self.parent[rootY] = rootX
            elif self.rank[rootX] < self.rank[rootY]:
                self.parent[rootX] = rootY
            else:
                self.parent[rootY] = rootX
                self.rank[rootX] += 1

def max_score_mst(n, edges):
    if n == 1:
        return 0

    uf = UnionFind(n)

    edges.sort(key=lambda x: x[2], reverse=True)

    total_score = 0
    for u, v, score in edges:
        if uf.find(u - 1) != uf.find(v - 1):
            uf.union(u - 1, v - 1)
            total_score += score

    if len({uf.find(i) for i in range(n)}) == 1:
        return total_score
    else:
        return "No solution."

while 1:
    n, m = map(int, input().split())
    edges = []
    for _ in range(m):
        u, v, score = map(int, input().split())
        edges.append((u, v, score))

    print(max_score_mst(n, edges))

问题 F: 最小生成树(Prim)

题目描述

使用Prim算法求图的最小生成树(MST)

输入

每组数据分为两个部分,第一部分为图的点数n,和边数m,
第二部分为m行,每一行输入三个数字,前两个为两个顶点的编号,第三个为边权重。

输出

最小生成树,输出时按照边的两个端点的升序输出。(先看左端点,再看右端点,端点不换位置)

样例输入 Copy
3 3
0 1 10
0 2 15
1 2 50
样例输出 Copy
0 1 10
0 2 15
def judge(a, b, c, vis):
    # 判断边(a, b)是否连接了两个不同树的顶点
    return a not in vis and b not in vis

def find(x, parent):
    # 路径压缩
    if parent[x] != x:
        parent[x] = find(parent[x], parent)
    return parent[x]

def union(x, y, parent):
    # 合并两个顶点所在的树
    rootX = find(x, parent)
    rootY = find(y, parent)
    if rootX != rootY:
        parent[rootY] = rootX

def kruskal(n, m, arr):
    parent = list(range(n))  # 并查集的父节点数组
    res = []
    cnt = 0  # 已加入MST的边的数量

    # 按权重对边进行排序
    arr.sort(key=lambda x: x[2])

    for a, b, c in arr:
        if cnt == n - 1:  # 如果已经找到n-1条边,退出循环
            break
        if judge(a, b, c, set(res)):  # 判断是否连接两个不同的树
            rootA = find(a, parent)
            rootB = find(b, parent)
            if rootA != rootB:  # 如果a和b不在同一个树中
                union(rootA, rootB, parent)  # 合并两个树
                res.append((a, b, c))  # 添加到结果中
                cnt += 1

    res.sort(key=lambda x: (x[0], x[1]))
    return res

n, m = map(int, input().split())
arr = []
for _ in range(m):
    arr.append(list(map(int, input().split())))

mst = kruskal(n, m, arr)

for edge in mst:
    print(*edge)

  • 13
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值