双向搜索 (Meet in the Middle / Bidirectional BFS)

核心思想

双向同时搜索:从起点和终点同时 BFS/DFS,两端相遇时即得可行解,搜索树大小大幅减小。

Meet in the Middle(折半搜索 / 中途相遇):将搜索过程分成两半,分别搜索,最后合并结果。适用于输入数据较小但不足以直接暴力的场景(如 )。

复杂度

暴力 → Meet in the Middle

实现(折半枚举 — P2962 开关灯)

#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
 
int n, m, ans = 0x7fffffff;
map<long long, int> f;
long long a[40];
 
int main() {
  cin >> n >> m;
  a[0] = 1;
  for (int i = 1; i < n; ++i) a[i] = a[i - 1] * 2;
  for (int i = 1; i <= m; ++i) {
    int u, v; cin >> u >> v;
    --u; --v;
    a[u] |= (1ll << v);
    a[v] |= (1ll << u);
  }
  // 前半
  for (int i = 0; i < (1 << (n / 2)); ++i) {
    long long t = 0; int cnt = 0;
    for (int j = 0; j < n / 2; ++j)
      if ((i >> j) & 1) t ^= a[j], ++cnt;
    if (!f.count(t)) f[t] = cnt;
    else f[t] = min(f[t], cnt);
  }
  // 后半
  for (int i = 0; i < (1 << (n - n / 2)); ++i) {
    long long t = 0; int cnt = 0;
    for (int j = 0; j < (n - n / 2); ++j)
      if ((i >> j) & 1) t ^= a[n / 2 + j], ++cnt;
    if (f.count(((1ll << n) - 1) ^ t))
      ans = min(ans, cnt + f[((1ll << n) - 1) ^ t]);
  }
  cout << ans;
  return 0;
}

练习

题目说明
P2962 USACO 灯 Lights折半枚举,
P4799 冰球meet in the middle 经典

相关链接

路径D-DSA算法刷题 | A星算法 | IDA星算法

来源:OI-wiki 双向搜索

多平台练习

| 洛谷 | 本题单 | 竞赛基础 |
| POJ (北大) | PKU JudgeOnline | 经典题目,适合巩固 |
| HDU (杭电) | HDU OJ | 暑期多校训练 |
| Codeforces | Codeforces | 国际竞赛,适合提升 |