tyvj/joyoi 1340 送礼物

论搜索顺序的优越性。

从小到大搜索,T到怀疑人生。

从大到小搜索,轻松AC。

 

双向搜索。

是这样的。我们首先排序一下,然后翻转。(当然也可以写cmp)

然后我们搜前半部分,把结果记录在某一数组中。

然后把结果排序(去重),再搜另一部分。

接下来有两种想法:

1.同样方式处理另一部分,然后双指针扫描。

2.第二次每次搜到终点,二分更新ans。

  还可以加上剪枝:如果当前的和加上后面所有再加上第一部分最大值都达不到ans,剪枝。

还可以用set,但是CE了...不知道为什么。

细节顺序还可以更优,但是我不想再去烦那台可怜的评测机了.....

进步已经很明显了。

下面上代码。(最优版)

 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 }
AC代码

 

posted @ 2018-06-19 13:17  garage  阅读(262)  评论(0编辑  收藏  举报