Loading [MathJax]/jax/output/CommonHTML/jax.js

搜索之meet in middle(有效的小方法)

题目:[https://www.luogu.com.cn/problem/P2962] (P2962 [USACO09NOV] Lights G)

算法:meet in middle(折半搜索)

思路:

35个点,总共的操作状态有235种情况。如果我们采用一般的搜索方式,时间上会毫不犹豫得爆掉。 所以,我们要用折半搜索的方式。将所有的点拆分成两个集合,对两个集合分别用搜索的方式(枚举所有可能出现的情况)。这样就只有O(2n/2)的时间复杂度了!也能顺利解决问题!

注意的细节:

1、用 longlong 代替 int 用来提高数据的承受能力。
2、提前预处理 2 的指数。
3、用 count 函数来计算1的个数。
4、对 << 与 >> 的正确使用。

点击查看代码
#include <algorithm>
#include <cstdio>
#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] |= ((long long)1 << v);
    a[v] |= ((long long)1 << 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((((long long)1 << n) - 1) ^ t))
      ans = min(ans, cnt + f[(((long long)1 << n) - 1) ^ t]);
  }

  cout << ans;

  return 0;
}
posted @   SSZX_loser_lcy  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示