poj 3977 折半枚举二分搜索
来源:互联网 发布:mysql输入密码后闪退 编辑:程序博客网 时间:2024/04/29 14:42
题意:
从n(35)个数字(有正有负)中取出一个非空子集,使得其和的绝对值最小。
若最小的绝对值有多组,则选择非空子集元素个数最少的。
解析:
折半来枚举。
将35分成两半,第一半状态压缩,然后用map离散化每个sum和num。
然后第二半还是状态压缩完了在map里面找最接近-sum的数。
ps,真是超级喜欢hankcs的c++代码风格。
- - 12s
代码:
#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <climits>#include <cassert>#define LL long longusing namespace std;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = 4 * atan(1.0);const double ee = exp(1.0);const int maxn = 30 + 10;LL a[maxn];LL Abs(LL x){ return x >= 0 ? x : -x;}int main(){#ifdef LOCAL freopen("in.txt", "r", stdin);#endif // LOCAL int n; while (~scanf("%d", &n) && n) { for (int i = 0; i < n; i++) { scanf("%lld", &a[i]); } map<LL, int> mp; // 未取绝对值的sum <-> 元素个数num pair<LL, int> ans(Abs(a[0]), 1); int inA = (n >> 1); int stA = (1 << inA); int inB = (n - (n >> 1)); int stB = (1 << inB); for (int i = 0; i < stA; i++) { LL sum = 0; int num = 0; for (int j = 0; j < inA; j++) { if ((i >> j) & 1) { sum += a[j]; num++; } } if (num == 0) continue; ans = min(ans, make_pair(Abs(sum), num)); map<LL, int>::iterator it = mp.find(sum); if (it != mp.end()) { it -> second = min(it -> second, num); } else { mp[sum] = num; } } for (int i = 0; i < stB; i++) { LL sum = 0; int num = 0; for (int j = 0; j < inB; j++) { if ((i >> j) & 1) { sum += a[inA + j]; num++; } } if (num == 0) continue; ans = min(ans, make_pair(Abs(sum), num)); map<LL, int>::iterator it = mp.lower_bound(-sum); if (it != mp.end()) { ans = min(ans, make_pair(Abs(sum + it -> first), num + it -> second)); } if (it != mp.begin()) { --it; ans = min(ans, make_pair(Abs(sum + it -> first), num + it -> second)); } } printf("%lld %d\n", Abs(ans.first), ans.second); } return 0;}
0 0
- poj 3977 折半枚举二分搜索
- POJ-3977-折半枚举,二分
- poj 3977 折半枚举+二进制枚举+二分
- 【折半枚举 && 二分】POJ
- POJ 3977 Subset (折半枚举+二分)
- codeforces888e(折半枚举+二分搜索)
- POJ 3977 Subset(折半枚举 + 二分查找)
- poj 3977 Subset 折半枚举
- POJ - 3977 Subset(折半枚举)
- POJ 3977 Subset (折半枚举)
- Poj 3977 Subset 折半枚举 超大背包
- POJ 3977 Subset (简单折半枚举)
- POJ 2785 折半枚举
- poj2785(二分折半枚举)
- 二分查找算法、折半搜索、二分搜索
- 折半枚举(双向搜索)
- 折半枚举(双向搜索)
- poj 3977 Subset 枚举+二分
- linux 性能分析工具
- 如何查看真机的沙盒(图文教程)
- 可变模板参数
- 黑马程序员_Java基础:实现多线程对共有数据的同步操作
- 亿信华辰成为大数据标准工作组成员单位
- poj 3977 折半枚举二分搜索
- 形参只能给实参,实参不能给形参!
- HDU - 1677Nested Dolls最长上升子序列变式
- 22,波形音频
- 南邮 OJ 1220 独立任务最优调度问题
- Button 点击事件onclick实现的四种方式
- opencv GPU函数
- ListView在显示的时候出现一行行包名
- eclipse中写java,html,css,javascript代码提示