xmuoj调制四果汤

调制四果汤

描述

四果汤是厦门地区的著名小吃。小明想喝四果汤,这个四果汤有n个元素(烧仙草、海石花、桃胶、椰果等),可以用n字母来表示。

小明在超市看到了T种配料,每种配料也会有一些元素,每个元素也可以用字母来表示(与上述四果汤的定义相同)。将不同的配料混合起来,即可得到一个元素为他们的并集的四果汤。

每种配料都有一个价格。现在小明想花尽量少的钱来购买配料,来调出自己想喝的四果汤,调出来的饮料必须具有他想喝的四果汤的所有特征。

出题人为李哲彦同学

输入

第一行两个数字T, n。表示配料的数量与四果汤特征的数量。

接下来T行,每行一个数字w,表示配料的价格,之后一个字符串,表示这个配料的元素。

T≤1000

n≤15

w≤10000

输出

一行一个整数,最小的价格。如果调不出来,则输出-1

输入样例 1 

4 3
5 C
6 B
16 BAC
4 A

输出样例 1

15

输入样例 2 

1 2
10 A

输出样例 2

-1

提示

样例1:小明想喝的四果汤元素为ABC,选择1、2、4种配料只需要15元,比选择第3种配料更便宜。

样例2:小明想喝的四果汤元素为AB,但是配料只有A,显然调不出来,故输出-1.

状态压缩DP

#include <iostream>
#include <vector>
#include <climits>

using namespace std;

int min_cost_to_create_four_fruit_soup(int T, int n, vector<pair<int, string>> &ingredients) {
    // 根据特征的数量计算 dp 数组的大小
    int dp_size = 1 << n;
    
    // 初始化 dp 数组,所有状态的成本都为一个非常大的数值(无穷大),除了状态 0(空集)的成本为 0
    vector<int> dp(dp_size, 1e9);
    dp[0] = 0;  // 空集的初始状态成本为 0

    // 遍历每一种配料
    for (int i = 0; i < T; i++) {
        int cost = ingredients[i].first;
        string elements = ingredients[i].second;
        
        // 将元素字符串转换为一个位掩码
        int mask = 0;
        for (char element : elements) {
            // 计算元素的位掩码
            mask |= (1 << (element - 'A'));
        }
        
        // 更新 dp 数组中的每一个可能状态
        // 我们从后往前迭代,避免在同一轮迭代中多次使用当前配料
        for (int current_mask = dp_size - 1; current_mask >= 0; current_mask--) {
            int new_mask = current_mask | mask;
            dp[new_mask] = min(dp[new_mask], dp[current_mask] + cost);
        }
    }

    // 目标状态是覆盖所有元素,对应于位掩码 (1 << n) - 1
    int target_mask = dp_size - 1;
    
    // 如果 dp[target_mask] 仍然是 INT_MAX,意味着我们找不到组合来覆盖所有元素
    // 否则,返回最小的成本
    return dp[target_mask] == 1e9 ? -1 : dp[target_mask];
}

int main() {
    int T ;
    int n;
    cin>>T>>n;
    vector<pair<int, string>> ingredients;
    for (int i = 0; i < T; i++) {
        int cost;
        string elements;
        cin >> cost >> elements;
        ingredients.push_back(make_pair(cost, elements));
    }

    int result = min_cost_to_create_four_fruit_soup(T, n, ingredients);
    cout << result << endl;  
    
    return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值