Divide and conquer:Sumsets(POJ 2549)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\\n", ans); 38 else 39 printf("no solution\\n"); 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\\n", ans); 37 else 38 printf("no solution\\n"); 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,我对他的做法表示怀疑)。
以上是关于Divide and conquer:Sumsets(POJ 2549)的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces - 1609A Divide and Multiply