$\newcommand{\O}{\mathrm{O}}$
01ナップサック問題の分割統治法を用いた解法. yukicoder のこれで出題されたもので愚直に $\O (nW)$ の DP ができないような制約に対して効果的である.
このスライド とかを見るとよいかも. 単純に 「価値 / 重さ」 の降順に並べて分割統治法を行っている.
(関数)
solve$(n, W, vec)$ : $n$ 個の商品 vec(価値, 重さ) を用いて, 重さ $W$ 以下で最大の価値を返す
void dfs(const int n, const long long W, const long long value, const long long weight, long long& opt, const int index, const vector<long long>& rsumw, const vector<int>& rminw, const vector<pair<int, int> >& vec) { if(index == n){ opt = max(opt, value); return; } if(rsumw[index] <= W - weight){ long long tvalue = value; for(int i = index; i < n; ++i){ tvalue += vec[i].first; } opt = max(opt, tvalue); return; } if(rminw[index] > W - weight) return; //使う if(weight + vec[index].second <= W){ opt = max(opt, value + vec[index].first); long long tweight = weight + vec[index].second, tvalue = value + vec[index].first; for(int i = index + 1; i < n; ++i){ if(tweight + vec[i].second <= W){ tweight += vec[i].second, tvalue += vec[i].first; }else{ tvalue += vec[i].first * (W - tweight) / vec[i].second; break; } } if(opt < tvalue){ dfs(n, W, value + vec[index].first, weight + vec[index].second, opt, index + 1, rsumw, rminw, vec); } } //使わない long long tweight = weight, tvalue = value; for(int i = index + 1; i < n; ++i){ if(tweight + vec[i].second <= W){ tweight += vec[i].second, tvalue += vec[i].first; }else{ tvalue += vec[i].first * (W - tweight) / vec[i].second; break; } } if(opt < tvalue){ dfs(n, W, value, weight, opt, index + 1, rsumw, rminw, vec); } } //vec には (価値, 重さ) の順で詰める long long solve(const int n, const long long W, vector<pair<int, int> >& vec) { sort(vec.begin(), vec.end(), [&](const pair<int, int>& a, const pair<int, int>& b){ return (long long)a.first * b.second > (long long)a.second * b.first; }); vector<long long> rsumw(n + 1, 0); vector<int> rminw(n + 1, numeric_limits<int>::max()); for(int i = n - 1; i >= 0; --i){ rsumw[i] = rsumw[i + 1] + vec[i].second, rminw[i] = min(rminw[i + 1], vec[i].second); } long long opt = 0; dfs(n, W, 0, 0, opt, 0, rsumw, rminw, vec); return opt; }
Atcoder : Sweet Alchemy
提出コード
yukicoder : Randomized 01 Knapsack
提出コード