首先比较容易想到是状态压缩DP
令$f[S]$表示选取了集合$S$以后,已经送了最少次数cnt且当前电梯剩下的体积rest最大(即$f[S]$是一个二元组(cnt, rest))
于是$f[S] = min_{i \in S} f[S - {i}] + v[i]$
$<$和$+$运算详情就请看程序好了,反正就是一个贪心思想,总复杂度$O(n * 2 ^ {n - 1})$
1 /************************************************************** 2 Problem: 2621 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:532 ms 7 Memory:13092 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <algorithm> 12 13 using namespace std; 14 const int N = 20; 15 const int S = 1 << N; 16 const int inf = 1e9; 17 18 int n, mx, mxs; 19 int a[S]; 20 21 struct data { 22 int cnt, rest; 23 data(int _c = 0, int _r = mx) : cnt(_c), rest(_r) {} 24 25 inline data operator + (int t) const { 26 static data res; 27 res = *this; 28 res.rest -= t; 29 if (res.rest < 0) ++res.cnt, res.rest += mx; 30 return res; 31 } 32 33 inline bool operator < (const data &d) const { 34 return cnt == d.cnt ? rest < d.rest : cnt < d.cnt; 35 } 36 } f[S]; 37 38 int main() { 39 int i, s, t, now; 40 scanf("%d%d", &n, &mx); 41 mxs = (1 << n) - 1; 42 for (i = 1; i <= n; ++i) scanf("%d", &a[1 << i - 1]); 43 f[0] = data(0, mx); 44 for (s = 1; s <= mxs; ++s) { 45 t = s, f[s] = data(inf, mx); 46 while (t) { 47 now = t & (-t); 48 f[s] = min(f[s], f[s ^ now] + a[now]); 49 t -= now; 50 } 51 } 52 printf("%d\n", f[mxs].cnt + (f[mxs].rest != mx)); 53 return 0; 54 } 55
时间: 2024-11-10 00:57:12