tyvj/joyoi 1340 送礼物
论搜索顺序的优越性。
从小到大搜索,T到怀疑人生。
从大到小搜索,轻松AC。
双向搜索。
是这样的。我们首先排序一下,然后翻转。(当然也可以写cmp)
然后我们搜前半部分,把结果记录在某一数组中。
然后把结果排序(去重),再搜另一部分。
接下来有两种想法:
1.同样方式处理另一部分,然后双指针扫描。
2.第二次每次搜到终点,二分更新ans。
还可以加上剪枝:如果当前的和加上后面所有再加上第一部分最大值都达不到ans,剪枝。
还可以用set,但是CE了...不知道为什么。
细节顺序还可以更优,但是我不想再去烦那台可怜的评测机了.....
进步已经很明显了。
下面上代码。(最优版)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <algorithm> 3 const int N = 50; 4 typedef long long LL; 5 6 int n, mid, t = -1; 7 LL a[N], b[1 << 23], W, ans, large, sum[N]; 8 9 void DFS1(int k, LL S) { 10 if(S > W) { 11 return; 12 } 13 if(S == W) { 14 printf("%lld", W); 15 exit(0); 16 } 17 if(k == mid + 1) { 18 b[++t] = S; 19 large = std::max(S, large); 20 return; 21 } 22 DFS1(k + 1, S); 23 DFS1(k + 1, S + a[k]); 24 return; 25 } 26 27 void DFS2(int k, LL S) { 28 if(S > W) { 29 return; 30 } 31 if(S == W) { 32 printf("%lld", W); 33 exit(0); 34 } 35 if(large + sum[k] + S <= ans) { /// 就是这里 36 return; 37 } 38 if(k == n + 1) { 39 int temp = std::upper_bound(b, b + t + 1, W - S) - b; 40 ans = std::max(ans, S + b[temp - 1]); 41 return; 42 } 43 DFS2(k + 1, S + a[k]); /// 这个顺序对应上面那个剪枝。 44 DFS2(k + 1, S); 45 return; 46 } 47 48 int main() { 49 scanf("%lld%d", &W, &n); 50 for(int i = 1; i <= n; i++) { 51 scanf("%lld", &a[i]); 52 } 53 std::sort(a + 1, a + n + 1); 54 std::reverse(a + 1, a + n + 1); 55 mid = (n + 1) >> 1; 56 for(int i = n; i >= mid; i--) { 57 sum[i] = sum[i + 1] + a[i]; 58 } 59 DFS1(1, 0); 60 std::sort(b, b + t + 1); 61 t = std::unique(b, b + t + 1) - b - 1; /// 注意reverse和unique的用法 62 DFS2(mid + 1, 0); 63 printf("%d", ans); 64 return 0; 65 }