171. 送礼物 题解

题目描述

avatar

解题思路

题解参考此处

代码

cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 46;  // k最大是25, 因此最多可能有2^25种方案
typedef long long ll;   

int n, m, k, cnt, res;
int w[N], weights[1 << 25];  // weights存储能凑出来的所有的重量

// u表示当前枚举到哪个数了, s表示当前的和
void dfs1(int u, int s)
{
    // 如果我们当前已经枚举完第k个数(下标从0开始的)了, 就把当前的s, 加到weights中去
    if (u == k)
    {
        weights[cnt++] = s;
        return;
    }

    // 枚举当前不选这个物品
    dfs1(u + 1, s);

    // 选这个物品, 做一个可行性剪枝(计算和的时候转成long long防止溢出)
    if ((ll)s + w[u] <= m)  dfs1(u + 1, s + w[u]);
}

void dfs2(int u, int s)
{
    if (u >= n)  // 如果已经找完了n个节点,二分找到答案(尽量大)
    {
        int l = 0, r = cnt - 1;
        while (l < r)
        { 
            int mid = l + r + 1 >> 1;
            if (weights[mid] <= m - s) l = mid;
            else r = mid - 1;
        }
        res = max(res, s + weights[l]);
        return;
    }
    
    // 不选择当前这个物品
    dfs2(u + 1, s);
    // 选择当前这个物品
    if ((ll)s + w[u] <= m) dfs2(u + 1, s + w[u]);
}

int main()      
{
    cin >> m >> n;
    for (int i = 0; i < n; i++) cin >> w[i];

    sort(w, w + n);
    reverse(w, w + n);  // 优化搜索顺序(从大到小)

    k = n / 2 + 2;  // 把前k个物品的重量打一个表(均衡复杂度,一般k=n/2)
    
    dfs1(0, 0);

    sort(weights, weights + cnt);  // 做完之后, 把weights数组从小到大排序
    cnt = unique(weights, weights + cnt) - weights;  // 判重

    // 从k开始, 当前的和是0
    dfs2(k, 0);  

    cout << res;
    return 0;
}
1126. 最小花费 题解
170. 加成序列 题解
Valaxy v1.0.0-rc.3 驱动|主题-Yunv1.0.0-rc.3