Divide and conquer:Sumsets(POJ 2549)

                

                  数集

  题目大意:给定一些数的集合,要你求出集合中满足a+b+c=d的最大的d(每个数只能用一次)

  这题有两种解法,

  第一种就是对分,把a+b的和先求出来,然后再枚举d-c,枚举的时候输入按照降序搜索就好,一旦d满足条件就是最大的了,另外判断不重复存一下位置就好,时间复杂度0(n^2*logn)

  

 1 #include <iostream>
 2 #include <functional>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 typedef long long LL_INT;
 8 static LL_INT input[1001];
 9 static pair<LL_INT, pair<int,int>>sums[1001 * 1001];
10 
11 LL_INT solve(const int, const int);
12 
13 bool cmp(const pair<LL_INT, pair<int, int>>&x, const pair<LL_INT, pair<int, int>>&y)
14 {
15     return x.first < y.first;
16 }
17 
18 int main(void)
19 {
20     LL_INT ans;
21     int num_sum, sum_comb;
22     while (~scanf("%d", &num_sum))
23     {
24         if (num_sum == 0) break;
25         for (int i = 0; i < num_sum; i++)
26             scanf("%lld", &input[i]);
27 
28         sort(input, input + num_sum);
29         sum_comb = 0;
30         for (int i = 0; i < num_sum; i++)
31             for (int j = i + 1; j < num_sum; j++)
32                 sums[sum_comb++] = make_pair(input[i] + input[j], make_pair(i, j));
33 
34         sort(sums, sums + sum_comb);
35         ans = solve(num_sum, sum_comb);
36         if (ans != INT_MAX)
37             printf("%lld
", ans);
38         else
39             printf("no solution
");
40     }
41     return EXIT_SUCCESS;
42 }
43 
44 LL_INT solve(const int num_sum, const int sum_comb)
45 {
46     int tmp[2] = { 0, 0 }, pos_s, pos_up;
47     for (int i = num_sum - 1; i >= 0; i--)
48     {
49         for (int j = num_sum - 1; j >= 0; j--)
50         {
51             if (i == j) continue;
52             pos_s = lower_bound(sums, sums + sum_comb, make_pair(input[i] - input[j], make_pair(0, 0)),cmp) - sums;
53             pos_up = upper_bound(sums, sums + sum_comb, make_pair(input[i] - input[j], make_pair(0, 0)),cmp) - sums;
54 
55             if (sums[pos_s].first == input[i] - input[j])
56             {
57                 for (int k = pos_s; k < pos_up; k++)
58                 {
59                     if (sums[k].second.first != i && sums[k].second.first != j
60                         &&sums[k].second.second != i && sums[k].second.second != j)
61                         return input[i];
62                 }
63             }
64         }
65     }
66     return (LL_INT)INT_MAX;
67 }

  

  剪枝了还是100+ms,太慢了,我不是很满意,去网上找了下果然有更快的做法

  其实像这种找固定数的题目都可以用散列来做,把a+b散列就好了,说实话好久没做散列我都忘记散列的那几条挺好用的公式了(貌似用书上那种散列方法效率更高),这里我就直接用链表法解决了

  参考http://www.cnblogs.com/CSU3901130321/p/4546190.html

  

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <functional>
 4 #define MOD 1001 * 1001
 5 
 6 using namespace std;
 7 
 8 static struct _set
 9 {
10     int val, num[2], next;
11 }memmory_pool[1001 * 1001];
12 static int Table[1001 * 1001], input[1001], tp;
13 
14 void Hash_To_Table(const int, const int, const int);
15 bool Search_Table(const int, const int, const int);
16 int solve(const int);
17 
18 int main(void)
19 {
20     int num_sum, sum_comb, ans;
21     while (~scanf("%d", &num_sum))
22     {
23         if (num_sum == 0)break;
24         for (int i = 0; i < num_sum; i++)
25             scanf("%d", &input[i]);
26         sort(input, input + num_sum);
27         sum_comb = num_sum*(num_sum - 1) / 2; tp = 0;
28 
29         fill(Table, Table + 1001 * 1001, -1);
30         for (int i = 0; i < num_sum; i++)
31             for (int j = i + 1; j < num_sum; j++)
32                 Hash_To_Table(input[i] + input[j], i, j);
33 
34         ans = solve(num_sum);
35         if (ans != INT_MAX)
36             printf("%d
", ans);
37         else
38             printf("no solution
");
39     }
40     return EXIT_SUCCESS;
41 }
42 
43 void Hash_To_Table(const int _int_value, const int i, const int j)
44 {
45     int pos = (_int_value > 0 ? _int_value : -_int_value) % MOD;
46     memmory_pool[tp].val = _int_value;
47     memmory_pool[tp].num[0] = i; 
48     memmory_pool[tp].num[1] = j;
49     memmory_pool[tp].next = Table[pos];
50     Table[pos] = tp++;
51 }
52 
53 bool Search_Table(const int _int_value, const int i, const int j)
54 {
55     int pos = (_int_value > 0 ? _int_value : -_int_value) % MOD;
56     for (int k = Table[pos]; k != -1; k = memmory_pool[k].next)
57     {
58         if (memmory_pool[k].val == _int_value)
59         {
60             if (memmory_pool[k].num[0] != i &&memmory_pool[k].num[1] != i
61                 &&memmory_pool[k].num[0] != j &&memmory_pool[k].num[1] != j)
62                 return true;
63         }
64     }
65     return false;
66 }
67 
68 int solve(const int num_sum)
69 {
70     for (int i = num_sum - 1; i >= 0; i--)
71     {
72         for (int j = num_sum - 1; j >= 0; j--)
73         {
74             if (i == j)continue;
75             if (Search_Table(input[i] - input[j], i, j))
76                 return input[i];
77         }
78     }
79     return INT_MAX;
80 }

  

  散列法复杂度是O(N^2),非常快。

  (另外有人在讨论版说他用O(n^3*logn)的时间复杂度方法94ms做出来了,我自己试了一下,如果他储存位置下标位置是一定会溢出的,不知道他怎么做出来的,而且就算是O(N^2*logn)的算法也是要用100+ms,我对他的做法表示怀疑)。

原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5174303.html