搜尋之雙向搜尋

2022-07-13 19:06:14 字數 2235 閱讀 8571

雙向搜尋是為了避免在深層子樹上浪費時間

有的問題有初態 和 終態

當我們從初態和終態雙向搜尋時,就相當已經搜尋了整個狀態空間

來看乙個例題吧

達達幫翰翰給女生送禮物,翰翰一共準備了n個禮物,其中第i個禮物的重量是g[i]。

達達的力氣很大,他一次可以搬動重量之和不超過w的任意多個物品。

達達希望一次搬掉盡量重的一些物品,請你告訴達達在他的力氣範圍內一次效能搬動的最大重量是多少。

輸入格式

第一行兩個整數,分別代表w和n。

以後n行,每行乙個正整數表示g[i]。

輸出格式

僅乙個整數,表示達達在他的力氣範圍內一次效能搬動的最大重量。

n <= 46

w <= 2^31 - 1

我們很容易想到揹包問題,不過太大導致陣列開不了,然後n比較小

如果暴力列舉是2^46肯定超時

不過我們可以採用雙向搜尋來搞

我們可以統計前一半的所有情況,複雜度是2^23 <=1e7

然後得到的排個序,對後半部分也可以列舉每一種情況,然後在前一半找出最優解可以二分出答案

所以後半部分是2^(n/2)*log(2^n/2)

然後這題還有乙個剪枝就是對於列舉的時候超出了w就直接回溯了

還有對於前一半重複的部分去重,也可以減少很多複雜度(去重用unique函式)

然後搜尋裡必須遵循的從決策數少的開始原則,可以把禮物從大到小排序,這樣列舉的時候就使得搜尋樹深度變小了

**:

#includeusing namespace std;

#define ll long long

const int n = 47;

ll g[n],a[1 << 23];

ll sum,w,ans;

int tot,n,cnt,up;

bool cmp(ll x,ll y)

void dfs1(int cur)

sum += g[cur];

if(sum <= w)

dfs1(cur + 1);

sum -= g[cur];

if(sum <= w)

dfs1(cur + 1);

}void dfs2(int cur,ll s)

else r = m - 1;

} if(s + x <= w) ans = max(ans,s + x);

return; }

if(s + g[cur] <= w) dfs2(cur + 1,s + g[cur]);

dfs2(cur + 1,s);

}int main()

不過這個地方還有個優化,就是數學關係吧

由於我們前半部分是n/2 複雜度是2^(n/2), 後半部分也是n/2複雜度是2^(n/2)*(log2^(n/2)),所以總的複雜度是2^(n/2)*(log2^(n/2))

後半部分是2^(n/2)*(log2^(n/2))起決定作用

我們如果讓前面多搜兩個禮物的話 複雜度變為

2^(n/2 + 2)*(log2^(n/2 - 2)是小於2^(n/2)*(log2^(n/2))的使前後的複雜度均衡了

#includeusing namespace std;

#define ll long long

const int n = 47;

ll g[n],a[1 << 23];

ll sum,w,ans;

int tot,n,cnt,up;

bool cmp(ll x,ll y)

void dfs1(int cur)

sum += g[cur];

if(sum <= w)

dfs1(cur + 1);

sum -= g[cur];

if(sum <= w)

dfs1(cur + 1);

}void dfs2(int cur,ll s)

else r = m - 1;

} if(s + x <= w) ans = max(ans,s + x);

return; }

if(s + g[cur] <= w) dfs2(cur + 1,s + g[cur]);

dfs2(cur + 1,s);

}int main()

事實證明確實如此

學到了

雙向寬度搜尋

從正反兩個方向進行寬度優先搜搜,可以大大減少搜尋量,提高搜尋速度。從初始狀態和目標狀態兩個方向同時進行擴充套件,如果兩顆解答樹在某個節點第一次發生重合,即可終止此搜尋過程,則該節點所連線的兩條路徑所拼成的路徑就是最優解。通常有兩種搜尋方式 1.兩個方向交替擴充套件 2.選擇節點個數較少的那個方向先擴...

折半列舉(雙向搜尋)

各有n個整數的四個數列a b c d。要從每個數列中各取乙個數,使四個數的和為0。求出這樣組合的個數。輸入n 6 a b c d 從4個數列中選擇共有n4種情況,全部判斷一遍不可行。不過將它們對半分成ab和cd再考慮,就可以快速解決了。從2個數列中選擇的話只有n2種組合,所以可以進行列舉。先從a b...

迭代加深和雙向搜尋

當答案的層數較低,並且搜尋的分支較多時,如果直接搜尋會消耗很多時間。這時候可以進行多次搜尋,每次搜尋可以限制乙個深度,如果我們在當前深度下搜尋不到答案,就增加深度限制,重新搜尋一邊答案,這樣 迭代 且 加深 的過程稱為迭代加深。但他的缺點也很明顯,每次需要重新搜尋一遍,所以在答案的層數比較深的時候不...