AcWing 171. 送禮物
阿新 • • 發佈:2022-03-10
一、題目解析
二、實現程式碼
#include <bits/stdc++.h> using namespace std; const int N = 48; // 1≤N≤46 typedef long long LL; int n; // N個禮物 int m; // 重量之和不超過m,上限,這是一個整數 int k; // 前k個,即索引下標0~k-1,最大值為N/2,就當25算 int w[N]; // 每個禮物的重量 int sum[1 << N / 2]; //前半段組合可能出現的所有和 //前半部分收集到的所有和,下標因為一直在保持++狀態,所以最後一次執行完,也可以理解為前半部分陣列的個數 //在排序去重後,此變更也可以視為前半段陣列的元素個數,在二分中,因為需要使用的是索引號:0~cnt-1 int cnt; int ans; //最大重量 // u:第幾號禮物,下標從0開始 // s:本路線上累加的禮物物理和 void dfs1(int u, int s) { if (u == k) { //如果能夠到達第k個下標位置,表示前面0~k-1共k個選擇完畢 sum[cnt++] = s; //記錄禮物重量和 return; } //放棄u號物品,走到下一個u+1號面前 dfs1(u + 1, s); //如果加上u號物品重量,不會超過上限m,那麼可以選擇 if ((LL)s + w[u] <= m) dfs1(u + 1, s + w[u]); } //後半部分 void dfs2(int u, int s) { if (u == n) { int l = 0, r = cnt - 1; //利用二分模板2,找出<=m的右邊界 while (l < r) { int mid = l + r + 1 >> 1; if ((LL)sum[mid] + s <= m) l = mid; else r = mid - 1; } //更新更大的重量 ans = max(ans, sum[l] + s); return; } //放棄當前禮物 dfs2(u + 1, s); //如果加上u號物品重量,不會超過上限m,那麼可以選擇 if ((LL)s + w[u] <= m) dfs2(u + 1, s + w[u]); } int main() { //先讀入m再讀入n,別整反了 cin >> m >> n; for (int i = 0; i < n; i++) cin >> w[i]; //每個禮物重量 //由大到小排序 sort(w, w + n, greater<int>()); //一家一半 k = n / 2; //前面開始搜尋 0~k-1 // dfs1,枚舉出了所有可能出現的組合值 dfs1(0, 0); //結果排序 sort(sum, sum + cnt); //去重 cnt = unique(sum, sum + cnt) - sum; //最後這個-1是換算出sum資料最後一個的下標 //後半部分搜尋 k~n dfs2(k, 0); //輸出答案 cout << ans << endl; return 0; }