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

题目地址:FZU 2178

由于n最大是30,一次全搜的话妥妥的超时,那么可以采用折半搜索。分成相同的两份,对左边的一堆进行预处理,然后再处理右堆,每一次都对左堆进行二分,找最接近的。由于两个人取的不能相差多于1个,所以要对每个个数分开存储。并排序,排序是为了后边的二分。

代码如下:

#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
using namespace std;
#define LL __int64
#define pi acos(-1.0)
const int mod=1e9+7;
const int INF=1e9;
const double eqs=1e-9;
int v[40], w[40], c[17][1<<15], d[17];
int bin_search(int x, int f)
{
        int low=0, mid, high=d[f]-1, ans=-1;
        while(low<=high){
                mid=low+high>>1;
                if(c[f][mid]>=x) {
                        ans=mid;
                        high=mid-1;
                }
                else low=mid+1;
        }
        if(ans==-1){
                return abs(c[f][d[f]-1]-x);
        }
        else if(ans==0){
                return abs(c[f][0]-x);
        }
        else return min(abs(c[f][ans]-x),abs(c[f][ans-1]-x));
}
int main()
{
        int t, n, i, min1, tot, m1, m2, ans1, ans2, al, ans, j, cnt;
        //freopen("1.txt","r",stdin);
        //freopen("2.txt","w",stdout);
        scanf("%d",&t);
        while(t--){
                scanf("%d",&n);
                m1=n>>1;
                m2=n-m1;
                min1=INF;
                for(i=0;i<n;i++){
                        scanf("%d",&v[i]);
                }
                for(i=0;i<n;i++){
                        scanf("%d",&w[i]);
                }
                if(n==1){
                        printf("%d\n",min(abs(v[0]-w[1]),abs(w[0]-v[1])));
                        continue ;
                }
                tot=1<<m1;
                memset(d,0,sizeof(d));
                memset(c,0,sizeof(c));
                for(i=0;i<tot;i++){
                        ans1=ans2=cnt=0;
                        for(j=0;j<m1;j++){
                                if(i&(1<<j)) {
                                                ans1+=v[j];
                                                cnt++;
                                }
                                else ans2+=w[j];
                        }
                        c[cnt][d[cnt]++]=ans1-ans2;
                }
                for(i=0;i<=m1;i++){
                        sort(c[i],c[i]+d[i]);
                }
                al=1<<m2;
                for(i=0;i<al;i++){
                        ans1=ans2=0;
                        cnt=0;
                        for(j=0;j<m2;j++){
                                if(i&(1<<j)) {
                                                ans1+=v[j+m1];
                                                cnt++;
                                }
                                else ans2+=w[j+m1];
                        }
                        ans=ans2-ans1;
                        //printf("%d\n",ans);
                        if((n&1)&&cnt){
                                min1=min(bin_search(ans,n/2+1-cnt),min1);
                        }
                        min1=min(bin_search(ans,n/2-cnt),min1);
                }
                printf("%d\n",min1);
        }
        return 0;
}

时间: 2024-10-08 18:42:05

FZU 2178 礼物分配 (折半搜索+二分)的相关文章

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组数组,每组

【bzoj4800】[Ceoi2015]Ice Hockey World Championship 折半搜索

题目描述 有n个物品,m块钱,给定每个物品的价格,求买物品的方案数. 输入 第一行两个数n,m代表物品数量及钱数 第二行n个数,代表每个物品的价格 n<=40,m<=10^18 输出 一行一个数表示购买的方案数 (想怎么买就怎么买,当然不买也算一种) 样例输入 5 1000 100 1500 500 500 1000 样例输出 8 题解 裸的折半搜索meet-in-the-middle 由于直接爆搜肯定会TLE,考虑把整个序列分成左右两部分,对于每部分求出它所有可以消耗钱数的方案.然后考虑左右

poj3977(折半枚举+二分查找)

题目链接:https://vjudge.net/problem/POJ-3977 题意:给一个大小<=35的集合,找一个非空子集合,使得子集合元素和的绝对值最小,如果有多个这样的集合,找元素个数最少的. 思路:显然,可以用折半搜索,分别枚举一半,最大是2的18次方,复杂度能够满足.因为集合非空,枚举时考虑只在前一半选和只在后一半选的情况.对于前一半后一半都选的情况,把前一半的结果存下来,排序,枚举后一半的时候在前一半里二分查找最合适的即可. 思路不难,实现有很多细节,最开始用dfs写得一直wa,

折半搜索(meet in the middle)

折半搜索(meet in the middle) ? 我们经常会遇见一些暴力枚举的题目,但是由于时间复杂度太过庞大不得不放弃. ? 由于子树分支是指数性增长,所以我们考虑将其折半优化; 前言 ? 这个知识点曾经在模拟赛中出现过,所以这里稍微提一下; ? 讲的很浅显,但是不要D讲者; 入门 ? dfs搜索树是指数性增长,如果将指数减少一半,就将会有量的飞跃,所以在遇见暴力枚举太大时,我们可以考虑这种算法; ? 总体思想即,dfs搜素通常从一个点出发,遍历所有深度,那么我们考虑将深度减半,从两个点出

POJ 2455 Secret Milking Machine(搜索-二分,网络流-最大流)

Secret Milking Machine Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9658   Accepted: 2859 Description Farmer John is constructing a new milking machine and wishes to keep it secret as long as possible. He has hidden in it deep within

HDU 4004 The Frog&#39;s Games(基本算法-贪心,搜索-二分)

The Frog's Games Problem Description The annual Games in frogs' kingdom started again. The most famous game is the Ironfrog Triathlon. One test in the Ironfrog Triathlon is jumping. This project requires the frog athletes to jump over the river. The

CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] Description Give you n packs, each of it has a value v and a weight w. Now you should find some packs, and the total of these value is max, total of

Eqs 折半枚举+二分查找 大水题

Eqs 题目抽象:a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 (*),给出a1,a2,a3,a4,a5.    ai属于[-50,50]. 求有多少序列   x1,x2,x3,x4,x5 ,xi属于 [-50,50]-{0}. 思路:折半枚举+二分查找 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #inclu

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