搜索是\(OI\)中一个十分基础也十分重要的部分,近年来搜索题目越来越少,逐渐淡出人们的视野。但一些对搜索的优化,例如\(A\)*,迭代加深依旧会不时出现。本文讨论另一种搜索——折半搜索\((meet\ in\ the\ middle)\)。

由一道例题引入:CEOI2015 Day2 世界冰球锦标赛

我们可以用以下代码解决\(n\leq 20\)的数据,时间复杂度\(O(2^n)\)

void dfs(int step, int sum)
{if (sum>m) return;if (step==n+1) {ans++; return;}dfs(step+1, sum+a[step]);dfs(step+1, sum);
}

\(dfs\)有何弊端?

当搜索层数增加时,时间复杂度增加过快。

可不可以减少搜索层数,甚至降至一半?

当然可以。不然我这篇文章写什么

看网上两张很好的图就一目了然了。

于是我们从\(1\)和\(n\)搜索\(\frac{n}{2}\)的深度,然后得到两个长为\(2^{\frac{n}{2}}\)的序列,对于第一个排序,然后用第二个在第一个中二分查找并统计答案即可。

(此代码不开\(O2\)在洛谷会\(T\)一个点,在\(loj\)跑的飞快,可能是满屏\(vector\)的缘故。)

#pragma GCC optimize (2)
#include<cstdio>
#include<vector>
#include<algorithm>
#define int long long
#define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
#define per(i, a, b) for (register int i=(a); i>=(b); --i)
using namespace std;
const int N=45;
vector<int> a, b;
int c[N], m, ans, n, mid;inline int read()
{int x=0,f=1;char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';return x*f;
}void dfs1(int step, int now)
{if (now>m) return;if (step>mid) {a.push_back(now); return;}dfs1(step+1, now+c[step]);dfs1(step+1, now);
}void dfs2(int step, int now)
{if (now>m) return;if (step>n) {b.push_back(now); return;}dfs2(step+1, now+c[step]);dfs2(step+1, now);
}signed main()
{n=read(); m=read(); mid=n+1>>1;rep(i, 1, n) c[i]=read();dfs1(1, 0); dfs2(mid+1, 0);sort(b.begin(), b.end());for (int i:a) ans+=upper_bound(b.begin(), b.end(), m-i)-b.begin();printf("%lld\n", ans);return 0;
}

再来看另一道例题:USACO12OPEN 平衡的奶牛群

可以看看官方题解。

有一种显然的暴力,子集枚举即可, 时间复杂度\(O(3^n)​\),无法通过。

我们把奶牛分为两组:黑色和白色。若\(S\)可行,那么\(S\)可被分为\(A,B\),使得\(sum_{A,black}-sum_{B,black}=sum_{B,white}-sum_{A,white}\)。于是我们可以计算黑色牛每一个子集可能的差值,白色同理。然后对于相同的差值进行配对,统计答案即可。

时间复杂度\(O(3^{\frac{n}{2}}\cdot 2^{\frac{n}{2}})\),即\(O((\sqrt{6})^n)\),可以通过。

依旧满屏\(vector\)

#include<cstdio>
#include<vector>
#include<algorithm>
#define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
#define per(i, a, b) for (register int i=(a); i>=(b); --i)
using namespace std;inline int read()
{int x=0,f=1;char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';return x*f;
}vector<pair<int, int> > solve(vector<int> S)
{vector<pair<int, int> > ans;int n=S.size(); rep(i, 0, (1<<n)-1)for (int j=i; ; j=(j-1)&i){int sum=0;rep(k, 0, n-1)if (j&(1<<k)) sum-=S[k];else if (i&(1<<k)) sum+=S[k];if (sum>=0) ans.push_back(make_pair(sum, i));if (!j) break;}sort(ans.begin(), ans.end());ans.resize(unique(ans.begin(), ans.end())-ans.begin());return ans;
}int main()
{int n=read();vector<int> P, Q;rep(i, 0, n-1) {int x=read();if (i&1) P.push_back(x);else Q.push_back(x);}vector<pair<int, int> > L=solve(P), R=solve(Q);int p=0, q=0, l=L.size(), r=R.size();vector<bool> vis(1<<n);while (p<l && q<r){if (L[p].first<R[q].first) p++;else if (L[p].first>R[q].first) q++;else{int p2=p, q2=q;while (p2<l && L[p2].first==L[p].first) p2++;while (q2<r && R[q2].first==R[q].first) q2++;rep(i, p, p2-1) rep(j, q, q2-1) vis[L[i].second|(R[j].second<<P.size())]=true,p=p2; q=q2;}}int ans=count(vis.begin()+1, vis.end(), true);printf("%d\n", ans);return 0;
}

SP4580 ABCDEF

即\(a*b+c=d*(e+f),d\neq 0\)。先枚举前三个,后三个枚举后二分查找即可。

#include<cstdio>
#include<vector>
#include<algorithm>
#define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
#define per(i, a, b) for (register int i=(a); i>=(b); --i)
using namespace std;
vector<int> b, v, w;
int a[105], n; long long ans;inline int read()
{int x=0,f=1;char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';return x*f;
}void prep()
{rep(i, 1, n) rep(j, 1, n) rep(k, 1, n)b.push_back(a[i]*a[j]+a[k]);sort(b.begin(), b.end());for (int i=0, j=0; i<b.size(); i=j+1, j++){while (j<b.size()-1 && b[j+1]==b[i]) j++;v.push_back(b[i]); w.push_back(j-i+1);}
}int check(int x)
{int p=lower_bound(v.begin(), v.end(), x)-v.begin();if (v[p]==x) return w[p]; else return 0;
}void calc()
{rep(i, 1, n) rep(j, 1, n) rep(k, 1, n)if (a[i]) ans+=check((a[j]+a[k])*a[i]);
}int main()
{n=read(); rep(i, 1, n) a[i]=read();prep(); calc();printf("%lld\n", ans);return 0;
}

转载于:https://www.cnblogs.com/ACMSN/p/10752201.html

Meet in the middle相关推荐

  1. CF888E Maximum Subsequence (Meet in the middle,贪心)

    题目链接 Solution Meet in the middle. 考虑到 \(2^{35}\) 枚举会超时,于是分成两半枚举(尽量平均). 然后不能 \(n^2\) 去匹配,需要用到一点贪心: 将数 ...

  2. 【搜索】【Meet in the middle】世界冰球锦标赛Ice Hockey World Championship

    题目描述 译自 CEOI2015 Day2 T1「Ice Hockey World Championship」 今年的世界冰球锦标赛在捷克举行.Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有 ...

  3. 骑士精神(双向深搜+meet in the middle)

    题目描述 在一个5×55×55×5的棋盘上有121212个白色的骑士和121212个黑色的骑士, 且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为111,纵坐标相差为22 ...

  4. E. XOR Guessing(Meet in the Middle)

    E. XOR Guessing(Meet in the Middle) 先把14位折半一下. 先取100个 高7位都为0的数,就可以确定xxx的高7位, 然后取100个低7位都为0的数,就可以确定xx ...

  5. CF888E Maximum Subsequence(meet in the middle)

    给一个数列和m,在数列任选若干个数,使得他们的和对m取模后最大( \(1<=n<=35\) , \(1<=m<=10^{9}\)) 考虑把数列分成两份,两边分别暴力求出所有的可 ...

  6. BZOJ.2679.Balanced Cow Subsets(meet in the middle)

    BZOJ 洛谷 \(Description\) 给定\(n\)个数\(A_i\).求它有多少个子集,满足能被划分为两个和相等的集合. \(n\leq 20,1\leq A_i\leq10^8\). \ ...

  7. 【洛谷 4799】 世界冰球锦标赛 Meet in the Middle 折半搜索

    题目描述 译自 CEOI2015 Day2 T1「Ice Hockey World Championship」 今年的世界冰球锦标赛在捷克举行.Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有 ...

  8. AAAI 2020 论文接收结果出炉,得分 997 论文被拒,388 反而中了?

    导语:无论这次中与不中,大家都要相信:我们的前程依旧光明与美好! 雷锋网 AI 科技评论:今天,就在广大民众都沉浸在双十一血拼之际,AAAI 2020 论文投稿作者从早上大约九点开始就相继收到了论文收 ...

  9. 资源下载 | 历年 AAAI 最佳论文(since 1996)

    导语:AAAI 2020 投稿已经过万,有小伙伴说29号投的时候才三千多,没想到31号就过万了,由此可见本次 AAAI 20220 竞争力非常激烈了. AAAI 2020 投稿已经过万,有小伙伴说29 ...

最新文章

  1. classname帝国怎么用php调用,帝国cms怎么调用栏目别名
  2. 访问“ for”循环中的索引?
  3. ubuntu1804系统设置在哪里_斐讯路由器k2如何刷机 斐讯路由器k2系统刷机教程【详解】...
  4. linux 关中断 调度,关中断是否禁止任务调度?关中断能作为互斥吗?
  5. 动态库在线更新导致coredump的问题
  6. vulfocus靶场安装教程
  7. oracle服务器和客户端字符集的查看和修改
  8. TensorFlow(1)-模型相关基础概念
  9. nginx 配置文件的匹配规则
  10. cut最后几位 shell_shell命令_cut
  11. ASP.NET MVC3 中整合 NHibernate3.3、Spring.NET2.0 使用AOP执行事务处理
  12. oracle读写mysql_Oracle读写磁盘经过的缓存
  13. 三菱M80加工中心伺服电机调试软件带序列号
  14. centos7配置时间同步服务器
  15. virtualbox 安装centeros
  16. 平面三角形与三角函数(1):角的度量与换算、三角函数的定义、图形与特征
  17. 默认连接电脑的模式为MTP
  18. PVLAN-配置案例(图)
  19. GN_2_使用GN编译自己写的程序
  20. Excel数据透视表经典教程五《功能选项卡》

热门文章

  1. [Android]ListView控件之Adapter性能优化
  2. Javascript 获取页面高度(多种浏览器)【转】
  3. 采用HttpModules来重写URLs(实践篇)
  4. 144.ipv4地址匮乏的解决方法
  5. 美国司法部将对大型科技公司展开广泛、新的反垄断审查
  6. c# groupbox大小,C# 实现可拖动和调整大小的控件
  7. Linux服务器上配置anaconda环境
  8. 消费者接收消息过程?
  9. String str =new String(“abc“)和 String str = “abc“的比较
  10. 004_LoadOnStartup