POJ 3977 折半搜索

Subset

Time Limit: 30000MS   Memory Limit: 65536K
Total Submissions: 4128   Accepted: 796

Description

Given a list of N integers with absolute values no larger than 1015, 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.

Input

The input contains multiple data sets, the first line of each data set contains N <= 35, the number of elements, the next line contains N numbers no larger than 1015 in absolute value and separated by a single space. The input is terminated with N = 0

Output

For each data set in the input print two integers, the minimum absolute sum and the number of elements in the optimal subset.

Sample Input

1
10
3
20 100 -100
0

Sample Output

10 1
0 2

Source

Seventh ACM Egyptian National Programming Contest

题意: 给n(n<=35)个数,求一个它的子集,使其中元素和的绝对值最小。

思路:分成两半来枚举。

代码:

#include "cstdio"
#include "stdlib.h"
#include "iostream"
#include "algorithm"
#include "string"
#include "cstring"
#include "queue"
#include "cmath"
#include "vector"
#include "map"
#include "set"
#define db double
#define inf 0x3f3f3f
#define mj
typedef long long ll;
using  namespace std;
const int N=4000*4000+5;
const int maxN=40;
typedef pair<ll,int> pii;
ll ab(ll x){
    return x>0?x:-x;
}
ll a[maxN];
int main()
{
    int n;
    while(cin>>n&&n){
        for(int i=0;i<n;++i) cin>>a[i];
        map<ll,int> m;
        pii res(ab(a[0]),1);
        for(int i=0;i<1<<(n/2);++i){
            ll sum=0;
            int num=0;
            for(int j=0;j<n/2;++j)
                if((i>>j)&1){
                    sum+=a[j];
                    ++num;
                }
            if(!num) continue;
            res=min(res,make_pair(ab(sum),num));//取最小值,优先级从前到后
            map<ll,int>::iterator iter=m.find(sum);
            if(iter!=m.end())
                iter->second=min(iter->second,num);
            else
                m[sum]=num;
        }
        for(int i=0;i<1<<(n-n/2);++i){
            ll sum=0;
            int num=0;
            for(int j=0;j<(n-n/2);++j)
                if((i>>j)&1){
                    sum+=a[n/2+j];
                    ++num;
                }
            if(!num) continue;
            res=min(res,make_pair(ab(sum),num));
            map<ll,int>::iterator iter=m.lower_bound(-sum);
            if(iter!=m.end())
                res=min(res,make_pair(ab(sum+iter->first),num+iter->second));
            if(iter!=m.begin()){
                --iter;
                res=min(res,make_pair(ab(sum+iter->first),num+iter->second));
            }
        }
        printf("%lld %d\n",res.first,res.second);
    }
    return 0;
}
时间: 2024-10-14 03:24:13

POJ 3977 折半搜索的相关文章

POJ 2785 折半搜索

https://vjudge.net/problem/POJ-2785 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<algorithm> #include<map> #define maxn 4005 typedef long long l

POJ 2329 (暴力+搜索bfs)

Nearest number - 2 Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 3943 Accepted: 1210 Description Input is the matrix A of N by N non-negative integers. A distance between two elements Aij and Apq is defined as |i ? p| + |j ? q|. Your pro

poj 3977 Subset

Subset Time Limit: 30000MS   Memory Limit: 65536K Total Submissions: 3662   Accepted: 673 Description Given a list of N integers with absolute values no larger than 1015, find a non empty subset of these numbers which minimizes the absolute value of

POJ 2918 Tudoku [搜索]

和POJ2676一样哈,,, 原谅我水题目数 = =!... #include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> using namespace std; int map[10][10]; char tmp[10][10]; bool row[10][10]; bool col[10][10]; bool grid[10][10]; bool DFS(int

poj 3977 Subset 枚举+二分

首先分成一半2^17和2^18,并且把其中一半变成相反数,然后枚举一半二分查找另一半,在找到的位置前后也找找. 这里用到了二级排序,有很多细节要处理,不多说了. 巨坑的一个地方就是,不能用系统的abs,要自己手写,简直坑死.. #include<cstdio> #include<algorithm> #include<iostream> #include<map> using namespace std; typedef long long ll; stru

E. Anya and Cubes (CF #297 (Div. 2) 折半搜索)

E. Anya and Cubes time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Anya loves to fold and stick. Today she decided to do just that. Anya has n cubes lying in a line and numbered from 1 to n

算法复习——哈希表+折半搜索(poj2549)

搬讲义~搬讲义~ 折半搜索感觉每次都是打暴力时用的啊2333,主要是用于降次··当复杂度为指数级别时用折半可以减少大量复杂度··其实专门考折半的例题并不多···一般都是中途的一个小优化··· 然后折半搜索常常与哈希表一起使用··尤其是遇到方程类的问题时··· 哈希表就不说了吧···毕竟比较简单···不懂得看下面题的代码就行了,一道折半与哈希表联合运用的经典方程模型题··· Description Given S, a set of integers, find the largest d suc

FZU 2178 礼物分配 (折半搜索+二分)

题目地址:FZU 2178 由于n最大是30,一次全搜的话妥妥的超时,那么可以采用折半搜索.分成相同的两份,对左边的一堆进行预处理,然后再处理右堆,每一次都对左堆进行二分,找最接近的.由于两个人取的不能相差多于1个,所以要对每个个数分开存储.并排序,排序是为了后边的二分. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <

位运算符 优先级 折半搜索

看编程珠玑,深知二分搜索的用处之大,自己写了一遍,竟然出了死循环.代码如下: 1 int bsearch(int *data, int val,int left, int right) 2 { 3 if(left <= right) 4 { 5 int mid = left + (right-left)>>1; 6 if(data[mid]==val) 7 return mid; 8 else if(data[mid]<val) 9 return bsearch(data,val,