东华OJ进阶30盾神与砝码称重

东华OJ进阶30盾神与砝码称重

问题描述

有一天,他在宿舍里无意中发现了一个天平!这个天平很奇怪,有n个完好的砝码,但是没有游码。盾神为他的发现兴奋不已!于是他准备去称一称自己的东西。他准备好了m种物品去称。神奇的是,盾神一早就知道这m种物品的重量,他现在是想看看这个天平能不能称出这些物品出来。但是盾神稍微想了1秒钟以后就觉得这个问题太难了,于是就丢给了你。

   注意:砝码可以和物品一起放在天平的同一边。

输入说明

第一行为两个数,n和m。
  第二行为n个数,表示这n个砝码的重量。
  第三行为m个数,表示这m个物品的重量。

  1<=n<=24, 1<=m<=10.

输出说明

输出m行,对于第i行,如果第i个物品能被称出,输出YES否则输出NO。

4 3
10 7 2 19
6 5 11

输出范例

NO
YES
YES

思路如下:

直接计算所有的情况会导致超时,故而采用分治的思想,将输入的砝码分为两个部分,然后分别求出两个部分的所有砝码放置可能出现的结果 sum1 和 sum2 集合。然后根据需要称量的结果 item,如果能在 sum2 中找到 item - sum1 的情况,那么就返回YES,否则就返回NO

代码实现

#include <iostream>
#include <vector>
#include <unordered_set>

using namespace std;

unordered_set<int> generate_sums(const vector<int>& ws) {
    unordered_set<int> sums = {0};
    for (int w : ws) {
        unordered_set<int> temp;
        for (int s : sums) {
            temp.insert(s + w);
            temp.insert(s - w);
            temp.insert(s);
        }
        sums = temp; 
    }
    return sums;
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<int> weights(n);
    for (int i = 0; i < n; ++i) {
        cin >> weights[i];
    }
    vector<int> items(m);
    for (int i = 0; i < m; ++i) {
        cin >> items[i];
    }

    int half = n / 2;
    vector<int> first_part(weights.begin(), weights.begin() + half);
    vector<int> second_part(weights.begin() + half, weights.end());

    auto sum1 = generate_sums(first_part);
    auto sum2 = generate_sums(second_part);

    for (int item : items) {
        bool found = false;
        for (int s1 : sum1) {
            if (sum2.count(item - s1)) {
                found = true;
                break;
            }
        }
        cout << (found ? "YES" : "NO") << '\n';
    }

    return 0;
}

用例详细解释

输入:

4 3
10 7 2 19
6 5 11

执行过程

  1. 砝码分组
first_part = [10, 7]

second_part = [2, 19]
  1. 生成组合
sum1 是 first_part 的所有组合:

{0, 10, -10, 7, -7, 17, -17, 3, -3}

sum2 是 second_part 的所有组合:

{0, 2, -2, 19, -19, 21, -21, 17, -17}
  1. 检查物品
物品 6:

检查是否存在 s1 + s2 = 6。

例如:s1 = 10,s2 = -4(不存在)。

最终没有找到,输出 NO。

物品 5:

例如:s1 = 7,s2 = -2(存在)。

输出 YES。

物品 11:

例如:s1 = 10,s2 = 1(不存在)。

但 s1 = 7,s2 = 4(不存在)。

最终没有找到,输出 NO。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值