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 ...