搜索之meet in middle(有效的小方法)
题目:[https://www.luogu.com.cn/problem/P2962] (P2962 [USACO09NOV] Lights G)
算法:meet in middle(折半搜索)
思路:
有个点,总共的操作状态有种情况。如果我们采用一般的搜索方式,时间上会毫不犹豫得爆掉。 所以,我们要用折半搜索的方式。将所有的点拆分成两个集合,对两个集合分别用搜索的方式(枚举所有可能出现的情况)。这样就只有的时间复杂度了!也能顺利解决问题!
注意的细节:
1、用 代替 用来提高数据的承受能力。
2、提前预处理 的指数。
3、用 函数来计算的个数。
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通