POJ 3977Subset
来源:互联网 发布:人工智能图像理解 编辑:程序博客网 时间:2024/06/07 10:51
Description
Given a list of N integers with absolute values no larger than 10 15, find a non empty subset of these numbers which minimizes the absolute value of the sum of its elements. In case there are multiple subsets, choose the one with fewer elements.
题意是给定n个数字,要求找到其一个非空子集,使得这个子集内绝对值的和最小。
类似的题目,由于很多数根本不会出现,而且数字非常大,一般来说都是折半搜索,先扫一边,在另一边用stl里的map查询有无,但是或许是因为自己写挫了的缘故,超时了。
所以最后我选择了用数组模拟,由于还有统计最少需要多少个,故开了一个结构体,v表示它的和,cnt表示构成它所需的次数,使用折半搜索的思想,折半先构造出前一半所能达到的和。接着构造后一半能达到的和sum,查找-sum是否能在前一半种找到,找不到就找最贴近的那一个。这时问题转换成了如何查找所有数内,与某个数最贴近的数,幸好c++算法库里自带lower_bound函数,算以我们可以在算出前一半时排序,在算后一半时边算达到的和sum,边查找-sum,由于最贴近的那一个如果-sum不存在,那就是大于-sum最小的值了,而需要的是绝对值,所以我们还要将这是lower_bound算出的pos-1,来求出小于-sum最大的值。注意lower_bound如果查不到返回的是右端点的值,所以如果这时pos如果是右端点,就给它-1,还要保证在求小于-sum最大的值时,pos-1是>0的。
下附AC代码
#include<iostream>#include<algorithm>#define maxn 40using namespace std;typedef long long ll ;int n;ll myabs(ll i){return i>=0 ? i : -i;}struct nod{ll v;int cnt;nod(ll a,int b){v=a;cnt=b;}nod(){}}a[1<<20];ll num[maxn];bool operator <(nod i,nod j){if(i.v!=j.v)return i.v<j.v;return i.cnt<j.cnt;}int main(){while(cin>>n && n){ll cnt1=0,cnt2=0;for(int i=0;i<n;i++)cin>>num[i];nod ans=nod(myabs(num[0]),1);int mid=n>>1;for(ll i=0;i<(1<<mid);i++){int ncnt=0;a[i].v=0;for(int j=0;j<mid;j++)if((i>>j) & 1){a[i].v+=num[j];ncnt++;}a[i].cnt=ncnt;if(i)ans=min(ans,nod(myabs(a[i].v),a[i].cnt));}sort(a,a+(1<<mid));for(ll i=0;i<(1<<mid)-1;i++)if(a[i].v==a[i+1].v){a[i+1].cnt=a[i].cnt;} for(ll i=1;i<(1<<(n-mid));i++){ll nsum=0;int ncnt=0;for(int j=0;j<n-mid;j++)if((i>>j) & 1){nsum+=num[mid+j];ncnt++;}nod now=nod(myabs(nsum),ncnt);ans=min(ans,now);ll pos=lower_bound(a,a+(1<<mid),nod(-nsum,0))-a;for(int j=min(pos,(long long)((1<<mid)-1));j>=max(pos-1,0ll);j--){ans=min(ans,nod(myabs(a[j].v+nsum),a[j].cnt+ncnt)); }}cout<<ans.v<<' '<<ans.cnt<<endl;}}
- POJ-3977-Subset
- poj 3977 Subset
- POJ 3977Subset
- POJ 3977Subset
- poj 3977 Subset 枚举+二分
- poj 3977 Subset 折半枚举
- POJ - 3977 Subset(折半枚举)
- POJ 3977 Subset 已翻译
- Subset POJ
- POJ 3977Subset(枚举+二分)
- POJ 3977 Subset (折半枚举)
- POJ 3977 Subset (折半枚举+二分)
- Poj 3977 Subset 折半枚举 超大背包
- POJ 3977 Subset (简单折半枚举)
- poj 3977 Subset(折半枚举+状压dp)
- POJ 3977 Subset(折半枚举 + 二分查找)
- subset
- Subset
- 我的第一篇博客
- 白话经典算法系列之八 白话经典算法之七大排序总结篇
- POJ-3669--Meteor Shower---BFS广搜
- JS三级数组对象过滤再取值
- MySQL的MyISAM与InnoDB的索引方式
- POJ 3977Subset
- Liunx怎么查看centos以及ubuntu版本
- jvm内存三大核心区域
- 高性能Server---Reactor模型
- php结合redis实现高并发下的抢购、秒杀功能
- Android开发之----proloader
- C语言——希尔排序
- lower_bound()返回值
- Caused by: java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 1