• POJ 3977 折半枚举


    链接:

    http://poj.org/problem?id=3977

    题意:

    给你n个数,n最大35,让你从中选几个数,不能选0个,使它们和的绝对值最小

    如果有一样的,取个数最小的 

    题解:

    np难题,但是因为数据小,所以可以通过折半枚举求解

    先枚举前一半的所有情况 用map记录下来,

    然后在枚举后一半的所有情况,再在前一半记录的map里面找相加的和 与0最接近的

    开始我用的set,但是set不好处理重复的

    不过map居然也可以用lower_bound!

    另外poj好像不支持long long的abs 所以要自己写一个

    代码:

     1 #include <map>
     2 #include <set>
     3 #include <cmath>
     4 #include <queue>
     5 #include <stack>
     6 #include <cstdio>
     7 #include <string>
     8 #include <vector>
     9 #include <cstdlib>
    10 #include <cstring>
    11 #include <sstream>
    12 #include <iostream>
    13 #include <algorithm>
    14 #include <functional>
    15 using namespace std;
    16 #define rep(i,a,n) for (int i=a;i<n;i++)
    17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
    18 #define pb push_back
    19 #define mp make_pair
    20 #define all(x) (x).begin(),(x).end()
    21 #define SZ(x) ((int)(x).size())
    22 typedef vector<int> VI;
    23 typedef long long ll;
    24 typedef pair<int, int> PII;
    25 const ll MOD = 1e9 + 7;
    26 const int INF = 0x3f3f3f3f;
    27 const double EPS = 1e-10;
    28 const double PI = acos(-1.0);
    29 const int MAXN = 8010;
    30 // head
    31 
    32 ll list[40];
    33 map <ll, int> mm;
    34 typedef pair<ll, int> pli;
    35 
    36 ll labs(ll x) {
    37     return x >= 0 ? x : -x;
    38 }
    39 
    40 int main() {
    41     int n;
    42     while (cin >> n, n) {
    43         mm.clear();
    44         rep(i, 0, n) scanf("%lld", list + i);
    45         pli ans = mp(1e18, 0);
    46         int n1 = n / 2, n2 = n - n1;
    47         rep(i, 1, 1 << n1) {
    48             ll sum = 0;
    49             int num = 0;
    50             rep(j, 0, n1) if (i&(1 << j)) sum += list[j], num++;
    51             if (!mm[sum] || mm[sum] > num) mm[sum] = num;
    52             pli t = mp(labs(sum), num);
    53             if (t < ans) ans = t;
    54         }
    55         rep(i, 1, 1 << n2) {
    56             ll sum = 0;
    57             int num = 0;
    58             rep(j, 0, n2) if (i&(1 << j)) sum += list[n1 + j], num++;
    59             pli t = mp(labs(sum), num);
    60             if (t < ans) ans = t;
    61             map<ll, int>::iterator k = mm.lower_bound(-sum);
    62             if (k != mm.end()) {
    63                 t = mp(labs((*k).first + sum), num + (*k).second);
    64                 if (t < ans) ans = t;
    65             }
    66             if (k != mm.begin()) --k;
    67             if (k != mm.end()) {
    68                 t = mp(labs((*k).first + sum), num + (*k).second);
    69                 if (t < ans) ans = t;
    70             }
    71         }
    72         cout << ans.first << ' ' << ans.second << endl;
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    December 23rd 2016 Week 52nd Friday
    December 22nd 2016 Week 52nd Thursday
    December 21st 2016 Week 52nd Wednesday
    December 20th 2016 Week 52nd Tuesday
    December 19th 2016 Week 52nd Sunday
    December 18th 2016 Week 52nd Sunday
    uva294(唯一分解定理)
    uva11624Fire!(bfs)
    fzu2150Fire Game(双起点bfs)
    poj3276Face The Right Way
  • 原文地址:https://www.cnblogs.com/baocong/p/6693060.html
Copyright © 2020-2023  润新知