zoukankan      html  css  js  c++  java
  • FZUOJ Problem 2178 礼品配送

                                                                                          Problem 2178 礼物分配


    题目链接: Click Here~ 

    Problem Description

    在双胞胎兄弟Eric与R.W的生日会上,他们共收到了N个礼物,生日过后他们决定分配这N个礼物(numv+numw=N)。对于每一个礼物他们俩有着各自心中的价值vi和wi,他们要求各自分到的礼物数目|numv-numw|<=1,而且各自所衡量的礼物价值的差值|sumv-sumw|尽可能小,如今他们想知道最小的差值是多少。

     Input

    第一行为一个整数表示数据组数T。 接下来T组数组,每组数据第一行为一个整数N。

    (N<=30) 第二行有N个整数,表示Eric所衡量的每一个礼物的价值vi。(1<=vi<=10000000) 第三行也有N个整数,表示R.W所衡量的每一个礼物的价值wi。(1<=wi<=10000000)

     Output

    对于每组数据。输出最小的差值。


    算法分析:
    能够easy想到的方法是直接枚举暴力。如今对第一个人来分析,每一个物品都有选或者不选的可能。

    这种话总情况是2^30次方。肯定超时。想着怎么优化。

    非常easy的想到了二分搜索。就是折半查找。

    思想就好是先预处理出前一半部分的结果。

    然后,在用前面的结果推断后面的情况。这样就能够优化到了2^15次方了。


    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    typedef __int64 LL;
    const int INF = 1 << 30;
    const int MAXN = 40;
    vector<int> num[MAXN];
    int vi[MAXN],wi[MAXN];
    
    int main() {
       int n,T;
       scanf("%d",&T);
       while(T--) {
           scanf("%d",&n);
           for(int i = 0;i < n;++i) {
               scanf("%d",&vi[i]);
           }
           for(int i = 0;i < n;++i) {
               scanf("%d",&wi[i]);
           }
    
           for(int i = 0;i <= n;++i)
             num[i].clear();
    
           int n2 = n/2;
           int cnt,sum1 ,sum2,sum;
           for(int S = 0;S < 1 << n2; ++S) {
              cnt = 0,sum1 = 0,sum2 = 0;
              for(int i = 0;i < n2;++i) {
                  if(S >> i & 1) {
                      sum1 += vi[i];
                      cnt++;
                  } else {
                      sum2 += wi[i];
                  }
              }
              num[cnt].push_back(sum1 - sum2);
           }
    
           for(int i = 0;i < n2;++i) {
               sort(num[i].begin(),num[i].end());
               num[i].erase(unique(num[i].begin(),num[i].end()),num[i].end());
           }
    
           int ans = INF;
           for(int S = 0;S < 1 << (n-n2);++S) {
               sum,cnt = 0,sum1 = 0,sum2 = 0;
               for(int i = 0;i < (n-n2);++i) {
                   if(S >> i & 1) {
                       sum1 += vi[i+n2];
                       cnt++;
                   } else {
                       sum2 += wi[i+n2];
                   }
               }
               int t = n - n2 - cnt;
               sum = sum1 - sum2;    
               vector<int>::iterator iter;
               iter = lower_bound(num[t].begin(),num[t].end(),-sum);
    
               if(iter != num[t].end() && abs(*iter + sum) < ans)
                   ans = abs(*iter + sum);
    
               if(iter != num[t].begin()) {
                    --iter;
                   if(abs(*iter + sum) < ans) ans = abs(*iter + sum);
               }
           }
    
            printf("%d
    ",ans);
       }
       return 0;
    }
    
    
    /*
    
    
    3
    1 2 3
    4 2 1
    
    5
    1 2 3 5 4
    1 1 1 1 5
    
    6
    1 2 3 4 5 5
    1 1 1 1 1 8
    
    */
    









    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    转!!javaMail使用网易163邮箱报535 Error: authentication failed
    银行卡验证(验证是否存在,卡号类型,归属行)
    Navicat已经成功连接,密码忘记的解决方法
    Inline&IAT Hook原理
    x64dbg尝鲜
    C# 通过Dynamic访问System.Text.Json对象
    dotnet5将asp.net webapi宿主到wpf
    Asp.Net5 MVC with Vue.js
    在 Visual Studio 中使用跟踪点将信息记录到“输出”窗口中
    WPF带阴影的无边框窗体
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4670678.html
Copyright © 2011-2022 走看看