日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Meet in the middle

發(fā)布時(shí)間:2025/4/16 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Meet in the middle 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

搜索是\(OI\)中一個(gè)十分基礎(chǔ)也十分重要的部分,近年來搜索題目越來越少,逐漸淡出人們的視野。但一些對(duì)搜索的優(yōu)化,例如\(A\)*,迭代加深依舊會(huì)不時(shí)出現(xiàn)。本文討論另一種搜索——折半搜索\((meet\ in\ the\ middle)\)

由一道例題引入:CEOI2015 Day2 世界冰球錦標(biāo)賽

我們可以用以下代碼解決\(n\leq 20\)的數(shù)據(jù),時(shí)間復(fù)雜度\(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\)有何弊端?

當(dāng)搜索層數(shù)增加時(shí),時(shí)間復(fù)雜度增加過快。

可不可以減少搜索層數(shù),甚至降至一半?

當(dāng)然可以。不然我這篇文章寫什么

看網(wǎng)上兩張很好的圖就一目了然了。

于是我們從\(1\)\(n\)搜索\(\frac{n}{2}\)的深度,然后得到兩個(gè)長(zhǎng)為\(2^{\frac{n}{2}}\)的序列,對(duì)于第一個(gè)排序,然后用第二個(gè)在第一個(gè)中二分查找并統(tǒng)計(jì)答案即可。

(此代碼不開\(O2\)在洛谷會(huì)\(T\)一個(gè)點(diǎn),在\(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 平衡的奶牛群

可以看看官方題解。

有一種顯然的暴力,子集枚舉即可, 時(shí)間復(fù)雜度\(O(3^n)?\),無法通過。

我們把奶牛分為兩組:黑色和白色。若\(S\)可行,那么\(S\)可被分為\(A,B\),使得\(sum_{A,black}-sum_{B,black}=sum_{B,white}-sum_{A,white}\)。于是我們可以計(jì)算黑色牛每一個(gè)子集可能的差值,白色同理。然后對(duì)于相同的差值進(jìn)行配對(duì),統(tǒng)計(jì)答案即可。

時(shí)間復(fù)雜度\(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\)。先枚舉前三個(gè),后三個(gè)枚舉后二分查找即可。

#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; }

轉(zhuǎn)載于:https://www.cnblogs.com/ACMSN/p/10752201.html

總結(jié)

以上是生活随笔為你收集整理的Meet in the middle的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。