# B 筱玛爱阅读

B 筱玛爱阅读

题目地址
题意:给定n个物品,m个方案,第i个方案包含个物品,现在共有n个价格,但不确定每一个物品属于哪一个价格。问买下所有物品需要的最小价格。
分析:
1. 简化问题,加入价格固定,就是一个状压dp,如果暴力递推,那么复杂度,不可接受,考虑采用枚举子集的方式复杂度
2. 现在考虑价格不固定,先把物品从大到小排序,考虑新加入的最后一个子集优惠的是最后一个元素即可

参考代码:

#include

using namespace std;

// 1 排序,从大到小
// 2 状压方案
// 3 枚举子集
const int maxn = 1 << 16;
int a[maxn];
int num[maxn], plan[maxn];
bool vis[maxn];
int dp[maxn];
int main(void) {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    sort(a + 1, a + n + 1);
    reverse(a + 1, a + n + 1);
    for (int i = 1; i <= m; ++i) {
        int k;
        scanf("%d", &k);
        for (int j = 1; j <= k; ++j) {
            int a; scanf("%d", &a);
            plan[i] |= 1 << (a - 1);
        }
        vis[plan[i]] = k;
    }
    for (int i = 0; i < (1 << n) - 1; ++i)
        num[i] = __builtin_popcount(i);
    int M = 0;
    for (int i = 1; i < (1 << n) - 1; ++i) {
        if (vis[i])
            dp[i] = max(dp[i], a[num[i]]);
        for (int s = i; s != 0; s = (s - 1)&i) {
            int x = i ^ s;
            if (!vis[x]) continue;
            dp[i] = max(dp[i], dp[s] + a[num[i]]);
        }
        for (int j = 0; j < n; ++j)
            dp[i | (1 << j)] = max(dp[i | (1 << j)], dp[i]);
        M = max(M, dp[i]);
    }
    int sum = 0;
    for (int i = 1; i <= n; ++i)
        sum += a[i];

    cout << sum - M << endl;

    return 0;
}

类似题目

  1. Sharing Chocolate UVALive - 4794
  2. Hackers' Crackdown UVA - 11825
全部评论

相关推荐

拉丁是我干掉的:把上海理工大学改成北京理工大学。成功率增加200%
点赞 评论 收藏
分享
霁华Tel:秋招结束了,好累。我自编了一篇对话,语言别人看不懂,我觉得有某种力量在控制我的身体,我明明觉得有些东西就在眼前,但身边的人却说啥也没有,有神秘人通过电视,手机等在暗暗的给我发信号,我有时候会突然觉得身体的某一部分不属于我了。面对不同的人或场合,我表现出不一样的自己,以至于都不知道自己到底是什么样子的人。我觉得我已经做的很好,不需要其他人的建议和批评,我有些时候难以控制的兴奋,但是呼吸都让人开心。
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务