送礼物(双向搜索)
達達幫翰翰給女生送禮物,翰翰一共準備了N個禮物,其中第i個禮物的重量是G[i]。
達達的力氣很大,他一次可以搬動重量之和不超過W的任意多個物品。
達達希望一次搬掉盡量重的一些物品,請你告訴達達在他的力氣范圍內一次性能搬動的最大重量是多少。
輸入格式
第一行兩個整數,分別代表W和N。
以后N行,每行一個正整數表示G[i]。
輸出格式
僅一個整數,表示達達在他的力氣范圍內一次性能搬動的最大重量。
emmmmm, 爆搜的話直接進行指數型枚舉——枚舉每個物品選還是不選, 時間復雜度為O(2n)。當然,若搜索過程中已選的禮物重量之和大于w, 可以及時剪枝。此題n <= 45 復雜度過高, 我們可以采取雙向搜索, 把禮物分成兩半。
首先,我們搜索出前一半禮物選出若干個, 可能到達0-w之間的所有重量值, 放在一個數組里, 對數組進行排序, 去重。
然后, 我們進行第二波搜索, 嘗試從后一半禮物中選出一些。對于每個可能達到的重量t,從第一部分得到的數組中二分查找<= w - t的數組中最大的一個, 用兩者的和更新答案
ps:取1 - n / 2 + 2 作為前一半, n / 2 + 3 - n為后一半, 搜索速度更快;
#include <bits/stdc++.h>using namespace std;typedef long long ll; const int INF = 0x3f3f3f3f; const int MAXN = 2e7 + 100; const int MAXM = 3e3 + 10;template < typename T > inline void read(T &x) {x = 0; T ff = 1, ch = getchar();while(!isdigit(ch)) {if(ch == '-') ff = -1;ch = getchar();}while(isdigit(ch)) {x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}x *= ff; }template < typename T > inline void write(T x) {if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + '0'); }ll w, n, top = 0, tot = 0, ans, a[MAXN], b[MAXN], c[MAXN];inline bool cmp(ll x, ll y) {return x > y; }ll find(ll x) {int l = 1, r = tot;while(l < r) {int mid = (l + r + 1) / 2;if(c[mid] <= x) l = mid;else r = mid - 1;}return c[l]; } void dfs(ll x, ll val) {if(x == n / 2 + 3) {b[++top] = val;return ;} if(val + a[x] <= w) dfs(x + 1, val + a[x]);dfs(x + 1, val); }void DFS(ll x, ll val) {if(x == n + 1) {ll u = find(w - val);ans = max(ans, u + val);return ;}if(val + a[x] <= w) DFS(x + 1, val + a[x]);DFS(x + 1, val); }int main() {read(w); read(n);for(int i = 1; i <= n; ++i)read(a[i]);sort(a + 1, a + n + 1,cmp);dfs(1, 0);sort(b + 1, b + top + 1);c[++tot] = 0;for(int i = 1; i <= top; ++i) {if(b[i] != b[i - 1]) c[++tot] = b[i];}DFS(n / 2 + 3, 0);write(ans);return 0; }?
轉載于:https://www.cnblogs.com/AK-ls/p/11276734.html
總結
- 上一篇: HttpUrlConnection使用详
- 下一篇: ubuntu apt 相关命令