折半枚举(双向搜索)

给定各有n个整数的四个数列,A,B,C,D。要从每个数列中各取1个数,使四个数的和为。求出这样的组合的个数,当一个数列中有多个相同的数字时,把他们作为不同的数字看待。

输入:n=6

A={-45, -41, -36, -36, 26, -32};

B={22 ,-27 ,53 ,30 ,-38 ,-54};

C={42 ,56 ,-37, 75, -10, -6};

D={-16 ,30, 77, -46, 62, 45};

输出:5(-45-27+42+30=0,26+30-10-46=0,-32+22+56-46=0,-32+30-75+77=0,-32-54+56+30=0)

分析:从这四个数列中选择的话总有n的4次方中情况,所以全部判断一遍不可行。不过将他们对半分成AB和CD再考虑的话就可以解决了。从两个数列中选择的话只有n的2次方中组合。所以可以枚举。从A,B中取出a,b后,为了使总和为0则需要从C,D中取出a+b=-(c+d);先将a和b数组的和存在一个数组ab里面,再将c和d相加的相反数-(c+d)在ab数组里面查找,用的是二分查找。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
    int a[4040];int b[4040];int ab[8080];
    int c[4040];int d[4040];
    int n;
    while(cin>>n)
    {
        for(int i=0;i<n;i++)
            cin>>a[i];
        for(int i=0;i<n;i++)
            cin>>b[i];
        for(int i=0;i<n;i++)
            cin>>c[i];
        for(int i=0;i<n;i++)
            cin>>d[i];
        int count1=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                ab[count1++]=a[i]+b[j];
          sort(ab,ab+n*n);
          int res=0;
          for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
              {
                  int cd=-(c[i]+d[j]);
                  res+=upper_bound(ab,ab+n*n,cd)-lower_bound(ab,ab+n*n,cd);
              }
              cout<<res<<endl;
    }
}
时间: 2024-10-25 16:29:07

折半枚举(双向搜索)的相关文章

折半枚举 双向搜索

从四个数列选择的话共有n的4次方种情况.将它们对半分成ab和cd再考虑以快速解决. 从两个数列中选择只有n的2次方种情况,可以进行枚举. 从c和d中取数字的n的平方种方法全都枚举出来排好序.运用二分搜索从中搜索-a[i]-b[j].复杂度O(n^2logn). #include<iostream> #include<math.h> #include<algorithm> #include<stdio.h> using namespace std; int n

超大背包问题(折半枚举, 双向搜索)

有重量和价值分别为wi, vi (1 <= wi, vi <= 1e15)的n (1 <= n <= 40)个物品,从中挑选总重不超过W(1 <= W <= 1e15)的物品,求价值总和最大值. 这是典型的01背包问题,不过dp求解复杂度为O(nW),这里W太大了,因此无法求解.挑选物品方法共有2^n种,也无法直接枚举.但是拆成两半再枚举的话还是可行的,每部分最多只有20个.假设第一部分某个选取方法对应的重量和价值为w1, v1,那么只要在第二部分中寻找w2+w1<

Load Balancing 折半枚举大法好啊

Load Balancing 给出每个学生的学分.   将学生按学分分成四组,使得sigma (sumi-n/4)最小.         算法:   折半枚举 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <string> 7 #include <

lightoj 1235 Coin Change (IV)(折半枚举)

话说这是俺们学校暑假集训完的一道题,刚看到以为是到水题,后来发现者复杂度也太大了,受不了了,比赛完也没搞出来,然后欣爷说这是折半枚举.然后就摸摸的学了一下,又把这道题写了一下, 所谓折半枚举就是先算出来一半,再算一半,然后用二分查找看看能不能搞到这一发状态,可以的话就是可以了, 题意:给你两个数n,k,下面再给你n个数,表示你现在有的硬币的面值,每种硬币面值的有两个,看是否可以支付k 题解思路:首先以为只有三种状态,直接dfs就好了,后来发现复杂度太大了,然后死了撸就是上面的,详细情残考代码 源

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

HDU 5340 Three Palindromes( 折半枚举+Manacher+记录区间 )

Three Palindromes Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 809    Accepted Submission(s): 240 Problem Description Can we divided a given string S into three nonempty palindromes? Input F

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

poj 2785 4 Values whose Sum is 0 折半枚举

题目链接:http://poj.org/problem?id=2785 枚举的一般思路就是先把所有的状态枚举出来 最后一次性判断该状态合法不合法 而折半枚举的思想是 先枚举一半的状态 把他们的状态存起来 排序 然后再枚举剩下一般 用目标反推前一半的期望状态 接下来在前一半的结果数组中查找是否有相应结果 之所以能优化是因为结果数组有序 就可以用二分搜索 复杂度从O(n^2 * n^2) 降到 O(n^2 * log(n^2))即(O(n^2 * log n)) 二分搜索的一个技巧 在有序数组中用二

LightOj 1076 - Get the Containers (折半枚举 绝世好题)

题目链接: http://www.lightoj.com/volume_showproblem.php?problem=1076 题目描述: 给出n个数,要求分成m段,问这m段中最大的总和,最小是多少? 解题思路: 二分每一段的长度,然后判定枚举长度是否合法. 刚看到这个题目就想到了dp,但是dp的复杂度还是很高的,然后就一直放着,放着....学了折半枚举,拿起来一看,哇塞,简直惊喜啊! 1 #include<cstdio> 2 #include<cstring> 3 #inclu

NYOJ 1091 超大01背包(折半枚举)

这道题乍一看是普通的01背包,最最基础的,但是仔细一看数据,发现普通的根本没法做,仔细观察数组发现n比较小,利用这个特点将它划分为前半部分和后半部分这样就好了,当时在网上找题解,找不到,后来在挑战程序设计上找到了这个题,就拿来引用一下 挑选物品的方法总从2^n中,直接枚举肯定不行,因为n最大为40,但是如果n为20就可以了,这时候就要用到折半枚举,先枚举前一半,在枚举后一半.先把前把部分的选取方法对应的重量和价值总和记为w1, v1,这样后半部分寻找w2 <= W - w1时 使v2最大的选取方