あいさか たいがblogAisaka_Taiga的博客
//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

Meet in the middle

Toretto·2023-07-05 10:00·71 次阅读

Meet in the middle

我们都知道搜索是非常常用的一个东西,我们在解决不了问题的时候就会选择他来暴力寻找最优解。

一般的暴力的复杂度都是指数级,比如常见的 01 背包,复杂度就是 O(2n),而如果我们用了 meet in the middle,就可以让我们的时间复杂度降到 O(2n2)

而他的思想也很简单,把问题从中间拆开,分成两部分来 DFS,一半是 1n2,一半是 n2+1n

然后在判断中间接起来的问题就可以了。

P2962 [USACO09NOV] Lights G#

我们看到数据范围,只有 35,我们考虑一下状压。

我们发现一个点只有两种状态,且一个改一个点会导致周围的点也都变,所以我们可以用一个数组,里面存放二进制数,每一位代表一个编号的点,1 表示白,0 表示黑。

我们在搜索的时候和上面一样分成两部分,我们用一个 map 来记录当前状态的最少步数,然后直接搜索即可。

Copy
#include <bits/stdc++.h> #define INF INT_MAX #define int long long #define N 10100 using namespace std; int mp[N], now, n, m, ans = INF; map<int, int> a; inline void dfs(int x, int u, int k, int t)//u是终点,k是当前状态,t是当前点的花费 { if(a[k]) a[k] = min(a[k], t); else a[k] = t; if(a[k ^ now] || k == now) ans = min(a[k ^ now] + t, ans); if(x <= u) { dfs(x + 1, u, k, t); k ^= mp[x]; dfs(x + 1, u, k, t + 1); } } signed main() { cin >> n >> m; for(int i = 1; i <= m; i ++) { int u, v; cin >> u >> v; mp[u] ^= (1 << v);//处理每一个与之相连的点 mp[v] ^= (1 << u); } for(int i = 1; i <= n; i ++) { mp[i] ^= (1 << i);//把每一个点都按位异或1 now ^= (1 << i); } dfs(1, n / 2, 0, 0);//折半搜索 dfs(n / 2 + 1, n, 0, 0); cout << ans << endl; return 0; }

P5691 [NOI2001] 方程的解数#

一看范围,有点大,一算,meet in the middle 能过。

我们分成两半后,不难发现一半和另一半的答案没有影响,我们直接用 map 来记录前半搜索的最后的 sum 值,然后第二半搜索的时候,直接加上 map[0sum] 就好了。

Copy
#include <bits/stdc++.h> #define int long long #define N 1000100 using namespace std; int n, m, k[N], p[N], ans; unordered_map<int, int> mp; inline void dfs(int x, int u, int sum, int ll) { if(x > u && ll == 1) return mp[sum] ++, void(); if(x > u && ll == 2) return ans += mp[0 - sum], void(); for(int i = 1; i <= m; i ++) dfs(x + 1, u, sum + k[x] * pow(i, p[x]), ll); return ; } signed main() { cin >> n >> m; for(int i = 1; i <= n; i ++) cin >> k[i] >> p[i]; int mid = n >> 1; dfs(1, mid, 0, 1); dfs(mid + 1, n, 0, 2); cout << ans << endl; return 0; }

Maximum Subsequence#

需要找模 m 后最大的值。

首先还是折半搜索出两部分的值,然后开始合并答案,我们有两种情况。

  1. mai+bi<2m,这个情况,我们就直接用两个数组中的最大值更新即可。

  2. ai+bi<m,这个情况,我们就可以直接一个从头,一个从尾开始,找最大的不大于 m 的值,然后取 max。

Copy
#include <bits/stdc++.h> #define int long long #define M 1001000 #define N 40 using namespace std; int n, P, mid, a[N], suma[M], cnta, sumb[M], cntb, ans, vis[N]; inline void dfs(int x, int u, int sum, int xx[], int &cnt) { if(x > u) return xx[++ cnt] = sum, void(); dfs(x + 1, u, sum, xx, cnt); dfs(x + 1, u, (sum + a[x]) % P, xx, cnt); return ; } signed main() { cin >> n >> P; for(int i = 1; i <= n; i ++) cin >> a[i], a[i] %= P; mid = n >> 1; dfs(1, mid, 0, suma, cnta); dfs(mid + 1, n, 0, sumb, cntb); sort(suma + 1, suma + cnta + 1); sort(sumb + 1, sumb + cntb + 1); ans = max(ans, (suma[cnta] + sumb[cntb]) % P); int l = cnta, r = 1; while(r <= cntb) { while(suma[l] + sumb[r] >= P) l --; ans = max(ans, suma[l] + sumb[r]); r ++; } cout << ans << endl; return 0; }

P4799 [CEOI2015 Day2] 世界冰球锦标赛#

我们还是分成两部分来搜索,我们用两个数组存起来不同的两部分的方案。

搜完之后,我们在最后枚举其中一个,然后就开始二分查找另一个里面与当前加起来不超过限制的数量,然后累加即可。

Copy
#include <bits/stdc++.h> #define int long long #define M 10000100 #define N 60 using namespace std; int n, m, w[N], suma[M], sumb[M], cnta, cntb, ans; inline void dfs(int l, int r, int sum, int a[], int &cnt) { if(sum > m) return ; if(l > r) return a[++ cnt] = sum, void(); dfs(l + 1, r, sum + w[l], a, cnt); dfs(l + 1, r, sum, a, cnt); return ; } signed main() { cin >> n >> m; for(int i = 1; i <= n; i ++) cin >> w[i]; int mid = n >> 1; dfs(1, mid, 0, suma, cnta); dfs(mid + 1, n, 0, sumb, cntb); sort(suma + 1, suma + cnta + 1); for(int i = 1; i <= cntb; i ++) ans += upper_bound(suma + 1, suma + cnta + 1, m - sumb[i]) - suma - 1; cout << ans << endl; return 0; }
posted @   北烛青澜  阅读(71)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
目录