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 ...
随机推荐
- 记一次jenkins发送邮件报错 一直报错 Could not send email as a part of the post-build publishers问题
写在前面 虽然Jenkins是开源.免费的,好处很多,但有些功能上的使用,我个人还是很不喜欢,感觉用起来特别麻烦.繁琐. 为什么? 就拿这个邮件配置来说吧,因重装系统,电脑需要配置很多东西,结果今天就 ...
- .NET MAUI发布了期待已久的候选版本(RC1)
作者:David Ortinau 我们激动地宣布在4/13/2022.NET多平台应用UI (.NET MAUI)发布了候选版本.SDK现在已经集成好了API,可以更新库,并为GA(通用可用性)兼容性 ...
- PostgreSQL与PostGIS安装使用时需要注意的坑
最近些许繁忙,没有时间系统整理PostgreSQL和PostGIS的安装和使用方法.所以就简单记录一下遇到的坑. 1.找不到 libintl-9.dll 我安装的PostgreSQL版本是11.7,P ...
- Win10系统链接蓝牙设备
1. 进入控制面板,选择 设备 2. 进入设备界面,删除已有蓝牙,如果蓝牙耳机已经链接其他设备,先断开链接 3. 点击添加蓝牙或其他设备 4. 选择蓝牙,选择你的蓝牙耳机名称
- SpringBoot从0到0.7——第二天
SpringBoot从0到0.7--第二天 今天来搭建一个登陆界面进行跳转,不带有数据库,看似就很简单的一个界面,却让我学习了好长时间去了解学习他的原理,能看懂的话还是尽量去看源码. 首先创建一个项目 ...
- windbg的时间旅行实现对 C# 程序的终极调试
一:什么是时间旅行 简而言之就是把程序的执行流拍成vlog,这样就可以对 vlog 快进或者倒退,还可以分享给别人做进一步的分析,是不是想都不敢想. 很开心的是 windbg preview 版本中已 ...
- C\C++白嫖学习
一.C语言的学习 推荐B站的郝斌老师的C语言教程,播放量可观.注意在学习前可在评论区"找宝藏". 大家可能也知道B站的小甲鱼,个人感觉内容不够优质,讲得有点粗糙,讲的故事有 ...
- 876. Middle of the Linked List - LeetCode
Question 876. Middle of the Linked List Solution 题目大意:求链表的中间节点 思路:构造两个节点,遍历链接,一个每次走一步,另一个每次走两步,一个遍历完 ...
- 词云图value传递数据不显示(已解决)
问题描述: 今天在做词云图时,虽然词云图能够展现出来,但是后台传递过来的数据(每个词出现的次数)却不显示. 错误原因: 错误的将tooltip写在了series内部,如图: 解决方案: 将toolti ...
- [BJOI2014]想法
参考 P4581传送门 题意:给DAG,问每个点可以由多少个叶子到达. 思路: 随机化!!(题面有提示) 这道题利用在一个范围内随机的数期望均分范围的性质. 直接每个叶子在\([0,Max\_Rand ...