(day16)称砝码

描述

现有n种砝码,重量互不相等,分别为 m1,m2,m3…mn ;
每种砝码对应的数量为 x1,x2,x3...xn 。现在要用这些砝码去称物体的重量(放在同一侧),问能称出多少种不同的重量。

注:称重重量包括 0

数据范围:每组输入数据满足 1≤𝑛≤10 , 1≤𝑚𝑖≤2000  , 1≤𝑥𝑖≤10 

输入描述:

对于每组测试数据:
第一行:n --- 砝码的种数(范围[1,10])
第二行:m1 m2 m3 ... mn --- 每种砝码的重量(范围[1,2000])
第三行:x1 x2 x3 .... xn --- 每种砝码对应的数量(范围[1,10])

输出描述:

利用给定的砝码可以称出的不同的重量数

示例1

输入:

2
1 2
2 1

输出:

5

说明:

可以表示出0,1,2,3,4五种重量。

 for堆砌


import sys
n = int(input())
wei_li = input().split()
num_li = input().split()
sum = {0}
for i in range(n):
    li = []
    for j in range(1,int(num_li[i])+1):
        wei = int(wei_li[i])*j
        li.append(wei)
    temp = sum.copy()
    for k in temp:
        for l in li:
            sum.add(k+l)
print(len(sum))

 这里如果定义sum为列表,后面再转换为集合会报错:内存超限

集合的基础知识

 集合内置方法完整列表如下:

 一些牛人的方法

import sys  # 导入sys模块

n = int(input())  # 从标准输入读取一个整数,并将其赋值给变量n
m = [int(i) for i in input().split(" ") if i]  # 从标准输入读取一行,以空格分隔,转换为整数列表,并赋值给变量m
x = [int(i) for i in input().split(" ") if i]  # 从标准输入读取另一行,以空格分隔,转换为整数列表,并赋值给变量x
mtype = {0}  # 初始化一个包含元素0的集合mtype

for i in range(n):  # 遍历范围为0到n-1的索引
    for j in range(x[i]):  # 根据x[i]的值,循环x[i]次
        # 计算当前mtype中每个元素加上m[i]的值,并将结果与原始mtype集合取并集
        mtype = {k+m[i] for k in mtype}.union(mtype)

print(len(mtype))  # 输出mtype集合的长度

集合推导式基本格式
 

{ expression for item in Sequence }或

{ expression for item in Sequence if conditional }

整体分析 

 该题实质是完全背包问题的一个变种,如果使用排列组合来找所有子集的方法时间复杂度高容易超时。(尝试过排列组合确实会很复杂)


使用动态规划算法解决


1. 定义状态:使用一个集合 possible_weights 来记录可能称出的所有重量。
2. 迭代每种砝码:对于每个砝码 m_i,在其对应的数量 x_i 之间进行迭代。   使用一个临时集合 new_weights 来保存当前迭代过程中产生的新重量。   对于现有的每个可能重量 w,添加 j * m_i(j 在 1 到 x_i 范围内),并将其添加到 new_weights 中。   最后,将 new_weights 中的所有重量添加到 possible_weights 中。
3. 计算所有可能重量:在完成所有砝码迭代后,possible_weights 应包含所有可能称出的重量。
4. 返回结果:possible_weights 的长度即为可能称出的不同重量数。  import sys

def count_possible_weights(n, weights, quantities):
    # 初始化可能称出的重量
    possible_weights = {0}  # 初始化为空重,集合中只有一个元素0

    # 迭代每种砝码
    for i in range(n):  # 遍历每种砝码
        current_weight = weights[i]  # 当前砝码的重量
        current_quantity = quantities[i]  # 当前砝码的数量
        # 新的可能重量集合
        new_weights = set()  # 初始化一个新的集合来存储当前轮新增的可能重量
        # 计算所有可能的重量
        for w in possible_weights:  # 遍历当前可能的所有重量
            for j in range(1, current_quantity + 1):  # 遍历当前砝码的数量
                new_weight = w + j * current_weight  # 计算新重量
                new_weights.add(new_weight)  # 将新重量加入新的集合
        # 合并到可能重量集合中
        possible_weights.update(new_weights)  # 将新的可能重量合并到总的可能重量集合中
    # 返回可能称出的不同重量数
    return len(possible_weights)  # 返回不同重量的数量

lines = []  # 初始化一个列表来存储输入数据
for line in sys.stdin:  # 从标准输入读取数据
    line = line.strip()  # 去除每行的前后空格
    if line == "":  # 如果读取到空行,结束读取
        break
    lines.append([int(i) for i in line.split(" ")])  # 将每行的数据分割并转换为整数列表,加入lines列表中

for i in range(len(lines) // 3):  # 处理每组输入数据,每组三行
    n = lines[i * 3][0]  # 第一行为砝码种类的数量
    weights = lines[i * 3 + 1]  # 第二行为每种砝码的重量列表
    quantities = lines[i * 3 + 2]  # 第三行为每种砝码的数量列表
    print(count_possible_weights(n, weights, quantities))  # 调用函数并输出结果

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值