zoukankan      html  css  js  c++  java
  • [2017浙工大之江学院决赛 E] qwb和李主席(折半枚举,二分)

    题目链接:http://115.231.222.240:8081/JudgeOnline/problem.php?cid=1005&pid=4

    题意:把一个数组拆成两部分,使得两个集合分别的和的差的绝对值最小。

    做过类似的,用01背包,求sum/2容量下的最大价值,这样可以拆成两个集合,并且符合题意。

    但是这题浮点数,而且物品价值1e9,不能背包了。

    n<=36,也不能直接枚举。

    可以把n个数拆成两部分,先枚举一部分的组合情况,把和求出来,再枚举另一部分,枚举到一个和x后在第一部分的和里二分地枚举一个和y,使得x+y最接近sum/2。然后每次更新两部分的和A=x+y, B=sum-A,更新ret=min(abs(A-B))即可。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 66;
     5 int n, na, nb;
     6 double v[maxn], a[maxn], b[maxn];
     7 double s[1<<20], sum;
     8 
     9 double gao(double val) {
    10     int lo = 1, hi = (1 << nb), ret = -1;
    11     while(lo <= hi) {
    12         int mid = (lo + hi) >> 1;
    13         if((s[mid] + val) * 2.0 >= sum) {
    14             ret = mid;
    15             hi = mid - 1;
    16         }
    17         else lo = mid + 1;
    18     }
    19     double A = s[ret] + val , B = sum - A;
    20     return abs(A - B);
    21 }
    22 
    23 int main() {
    24     // freopen("in", "r", stdin);
    25     while(~scanf("%d",&n)) {
    26         na = nb = 0;
    27         sum = .0;
    28         memset(s, 0, sizeof(s));
    29         for(int i = 1; i <= n; i++) {
    30             scanf("%lf", &v[i]);
    31             sum += v[i];
    32             if(i <= n / 2) a[na++] = v[i];
    33             else b[nb++] = v[i];
    34         }
    35         for(int i = 0; i < (1 << na); i++) {
    36             for(int j = 0; j < na; j++) {
    37                 if(i & (1 << j)) s[i+1] += a[j];
    38             }
    39         }
    40         sort(s+1, s+(1<<na)+1);
    41         double ret = 1e18;
    42         for(int i = 0; i < (1 << nb); i++) {
    43             double tmp = .0;
    44             for(int j = 0; j < nb; j++) {
    45                 if(i & (1 << j)) tmp += b[j];
    46             }
    47             // double A = tmp + *lower_bound(s+1, s+(1<<na)+1, sum/2.0-tmp);
    48             // double B = sum - A;
    49             ret = min(ret, gao(tmp));
    50         }
    51         printf("%.2f
    ", ret);
    52     }
    53     return 0;
    54 }
  • 相关阅读:
    游标cursor
    SQL: EXISTS
    LeetCode Reverse Integer
    LeetCode Same Tree
    LeetCode Maximum Depth of Binary Tree
    LeetCode 3Sum Closest
    LeetCode Linked List Cycle
    LeetCode Best Time to Buy and Sell Stock II
    LeetCode Balanced Binary Tree
    LeetCode Validate Binary Search Tree
  • 原文地址:https://www.cnblogs.com/kirai/p/6936947.html
Copyright © 2011-2022 走看看