题意
给定 $n$ 个物品,体积分别为 $v_i$,现有 $K$ 的容积一样的箱子,按如下策略装入物品:每次选取尽可能大的装入(较大的不能装入时可以向小的找),依次装入箱子。
分析
首先,不具有严格的单调性,即可能大的箱子不符合但小的符号。与我们的直觉有点不同,是这个策略造成的。
但是基本单调,最优解应该在二分结果附近,于是有了方法一。
方法二:找出答案的上下界,下界 $left lceil sum/k ight ceil$,上界 $ left lceil sum/k ight ceil + maxV$,枚举。
#include<bits/stdc++.h> using namespace std; const int maxn = 1000 + 10; int n,k,a[maxn]; multiset<int>st; bool judge(int mid) { st.clear();int tmpk = k; for(int i = 0;i < n;i++) st.insert(a[i]); while(!st.empty() && tmpk--) { int x = mid; while(x) { multiset<int>::iterator it = st.upper_bound(x); //第一个小于或等于x if(it == st.begin()) break; it--; x -=*it; st.erase(it); } } if(!st.empty()) return false; return true; } int main() { int T, kase=0; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &k); for(int i = 0;i < n;i++) { scanf("%d", &a[i]); } int l = 1, r = 1000000, ans; while(l < r) { int mid = (l+r)>>1; if(judge(mid)) { ans = mid; r = mid-1; } else l = mid+1; } int res = ans; //printf("%d ", ans); for(int i = max(1, ans-100);i <= ans;i++) //往小一点尝试一下 if(judge(i)) { res = i; break; } printf("Case #%d: %d ", ++kase, res); } return 0; }
参考链接:
1. https://ac.nowcoder.com/acm/contest/view-submission?submissionId=41019801
2. https://ac.nowcoder.com/acm/contest/view-submission?submissionId=41026089