meet in the middle 复习笔记
前言
若干年前看过现在又忘了。这么简单都忘
所以今天来重新复习一下。
正题
考虑这样的问题:
给定 \(n\) 个物品的价格,你有 \(m\) 块钱,每件物品限买一次,求买东西的方案数。
\(n\leq 40\),\(m\leq 10^{18}\)。
在看到数据范围之前,所有人的想法都是直接背包,看到数据范围后就寄了。
看样子不可用背包,那就用搜索吧。
直观的,我们考虑 \(O(2^n\times n)\) 的做法。
用 \(O(2^n)\) 的复杂度枚举每个物品是否购买,再 \(O(n)\) 复杂度判断是否合法。
但是看懂 \(n \leq 40\) 时就又寄了。
这是我们考虑 meet in the middle ,把时间复杂度变成 \(O(2^{\frac{n}{2}}+合并复杂度)\) 。
我们直接把当前的物品分成 \(1\sim \frac{n}{2}\) 和 \(\frac{n}{2}+1 \sim n\) 两个部分。
对于每一个部分我们都进行搜索,并把当前方案的花费 分两个数组 记录下来。
不难发现,到这为止,时间复杂度是 \(O(n^{\frac{n}{2}})\) 带有 \(2\) 的常数。
考虑怎么处理计算出来的各种方案的花费。
先考虑其中一个数组中的一种花费必选,然后直接二分查找即可。
(当然,之前要对这两个数组进行排序)
Code
笔者远古代码,没有人肉格式化,不喜勿喷。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define ll long long
#define re register
#define N 50
#define M 2000005
int max(ll a,ll b){return a>b?a:b;}
int min(ll a,ll b){return a<b?a:b;}
int n,num,visit[N];
ll m,a[N],num1[M],num2[M];
ll b[N],c[N],ans=0;
inline ll read(){
  ll s=0,t=1;
  char c=getchar();
  while((c<'0'||c>'9')&&c!='-')c=getchar();
  if(c=='-')c=getchar(),t=-1;
  while(c>='0'&&c<='9')s=(s<<1)+(s<<3)+(c^48),c=getchar();
  return s*t;
}
void dfs_b(int k){
  if(k>b[0]){
    ll s=0;
    for(int i=1;i<=b[0];i++)
    if(visit[i]==1)s+=b[i];
    num1[++num1[0]]=s;
    return;
  }
  visit[k]=1;
  dfs_b(k+1);
  visit[k]=0;
  dfs_b(k+1);
}
void dfs_c(int k){
  if(k>c[0]){
    ll s=0;
    for(int i=1;i<=c[0];i++)
    if(visit[i]==1)s+=c[i];
    num2[++num2[0]]=s;
    return;
  }
  visit[k]=1;
  dfs_c(k+1);
  visit[k]=0;
  dfs_c(k+1);
}
ll find(ll need){
  ll l=1,r=num2[0];
  ll mid,maxn=0;
  while(l<=r){
    mid=(l+r)/2;
    if(num2[mid]<=need){
      maxn=max(maxn,mid);
      l=mid+1;
    }
    else r=mid-1;
  }
  return maxn;
}
int main(void){
  scanf("%d",&n);
  m=read();
  for(int i=1;i<=n;i++)
  a[i]=read();
  num=n/2;
  for(int i=1;i<=num;i++)
  b[++b[0]]=a[i];
  for(int i=num+1;i<=n;i++)
  c[++c[0]]=a[i];
  memset(visit,0,sizeof(visit));
  dfs_b(1);
  memset(visit,0,sizeof(visit));
  dfs_c(1);
  sort(num2+1,num2+1+num2[0]);
  for(int i=1;i<=num1[0];i++){
    ll now=m-num1[i];
    if(now<0ll)continue;
    ans+=find(now);
  }
  printf("%lld\n",ans);
}
meet in the middle 复习笔记的更多相关文章
- Meet in the middle学习笔记
		Meet in the middle(MITM) Tags:搜索 作业部落 评论地址 PPT中会讲的很详细 当搜索的各项互不影响(如共\(n\)个物品前\(n/2\)个物品选不选和后\(n/2\)个物 ... 
- Java基础复习笔记系列 九 网络编程
		Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ... 
- Java基础复习笔记系列 八 多线程编程
		Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ... 
- Java基础复习笔记系列 七 IO操作
		Java基础复习笔记系列之 IO操作 我们说的出入,都是站在程序的角度来说的.FileInputStream是读入数据.?????? 1.流是什么东西? 这章的理解的关键是:形象思维.一个管道插入了一 ... 
- Java基础复习笔记系列 五 常用类
		Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ... 
- Java基础复习笔记系列 四 数组
		Java基础复习笔记系列之 数组 1.数组初步介绍? Java中的数组是引用类型,不可以直接分配在栈上.不同于C(在Java中,除了基础数据类型外,所有的类型都是引用类型.) Java中的数组在申明时 ... 
- Java基础复习笔记基本排序算法
		Java基础复习笔记基本排序算法 1. 排序 排序是一个历来都是很多算法家热衷的领域,到现在还有很多数学家兼计算机专家还在研究.而排序是计算机程序开发中常用的一种操作.为何需要排序呢.我们在所有的系统 ... 
- Meet in the middle
		搜索是\(OI\)中一个十分基础也十分重要的部分,近年来搜索题目越来越少,逐渐淡出人们的视野.但一些对搜索的优化,例如\(A\)*,迭代加深依旧会不时出现.本文讨论另一种搜索--折半搜索\((meet ... 
- SPOJ4580 ABCDEF(meet in the middle)
		题意 题目链接 Sol 发现abcdef是互不相关的 那么meet in the middle一下.先算出abc的,再算def的 注意d = 0的时候不合法(害我wa了两发..) #include&l ... 
随机推荐
- 被人DDoS攻击了,分析一下原理和防护
			一.行业现象 1.1 为什么要攻击? 常见的,一个是同行恶意竞争,一个是敲诈勒索. 无论是传统行业的线下门店,还是互联网行业的门户网站.APP产品,都存在着竞争关系,争相获得更多客源,究其目的,无非是 ... 
- 深入浅出聊Taier—大数据分布式可视化DAG任务调度系统
			导读: 上周,袋鼠云数栈全新技术开源规划--DTMO(DTstack Meetup Online)的第一场直播圆满完成.袋鼠云数栈大数据开发专家.Taier项目主导人偷天为大家带来了<Taier ... 
- XCTF练习题---MISC---如来十三掌
			XCTF练习题---MISC---如来十三掌 flag:flag{bdscjhbkzmnfrdhbvckijndskvbkjdsab} 解题步骤: 1.观察题目,下载附件进行查看 2.打开附件,压根看 ... 
- 使用 Python 来自动回微信
			准备 Python3 Python Itchat库(可以通过pip install itchat来安装) (可选)Python Pymongo库(可以通过pip install pymongo来安装) ... 
- 论文解读《Measuring and Relieving the Over-smoothing Problem for Graph NeuralNetworks from the Topological View》
			论文信息 论文标题:Measuring and Relieving the Over-smoothing Problem for Graph NeuralNetworks from the Topol ... 
- 实战  target 选择器,解放生产力!
			大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ... 
- 版本控制之git
			1.Git的介绍 Git 是一个开源的分布式版本控制软件,用以有效.高速的处理从很小到非常大的项目版本管理. Git 最初是由Linus Torvalds设计开发的,用于管理Linux内核开发.Git ... 
- 278. First Bad Version - LeetCode
			Question 278. First Bad Version Solution 题目大意:产品有5个版本1,2,3,4,5其中下一个版本依赖上一个版本,即版本4是坏的,5也就是坏的,现在要求哪个版本 ... 
- 使用 Postman 实现 API 自动化测试
			背景介绍 相信大部分开发人员和测试人员对 postman 都十分熟悉,对于开发人员和测试人员而言,使用 postman 来编写和保存测试用例会是一种比较方便和熟悉的方式.但 postman 本身是一个 ... 
- hexo + typora 图片插入解决办法
			Typora 是一款知名的 Markdown 编辑器,简单好用,体验良好.使用 hexo 搭建好博客后,主要是用 Markdown 来编写博客,typora 便是我的首选编辑器.但直接使用 typor ... 
