演算法都是套路系列 搜尋技術模板 3

2021-10-24 13:13:22 字數 4766 閱讀 6888

將整個搜尋過程分成兩半,分別搜尋,最後將兩半的結果合併。由於搜尋的複雜度往往是指數級的,而折半搜尋可以使指數減半,也就能使複雜度開方。

有n 盞燈,每盞燈與若干盞燈相連,每盞燈上都有乙個開關,如果按下一盞燈上的開關,這盞燈以及與之相連的所有燈的開關狀態都會改變。一開始所有燈都是關著的,你需要將所有燈開啟,求最小的按開關次數。

?分析如果這道題暴力 dfs 找開關燈的狀態,時間複雜度就是 o(2^n), 顯然超時。不過,如果我們用meet-in-middle的話,時間複雜度可以優化至 o(n2^(n/2))。meet-in-middle就是讓我們先找一半的狀態,也就是找出只使用編號為 1到mid 的開關能夠到達的狀態,再找出只使用另一半開關能到達的狀態。如果前半段和後半段開啟的燈互補,將這兩段合併起來就得到了一種將所有燈開啟的方案。具體實現時,可以把前半段的狀態以及達到每種狀態的最少按開關次數儲存在 map 裡面,搜尋後半段時,每搜出一種方案,就把它與互補的第一段方案合併來更新答案。

c++

#include #include #include #include using namespace std;

typedef long long ll;

int n, m, ans = 0x7fffffff;

mapf;

ll a[40];

int main()

for (int i = 0; i < (1 << (n / 2)); ++i)

}if (!f.count(t))

f[t] = cnt;

else

f[t] = min(f[t], cnt);

} for (int i = 0; i < (1 << (n - n / 2)); ++i)

}if (f.count(((1ll << n) - 1) ^ t))

ans = min(ans, cnt + f[((1ll << n) - 1) ^ t]);

} cout << ans;

return 0;

}

啟發式搜尋就是對取和不取都做分析,從中選取更優解(或刪去無效解)

輔助資訊

所求解問題之外、與所求解問題相關的特定資訊或知識

評價函式(evaluation function)f(n)

從當前節點n出發,根據評價函式來選擇後續節點

啟發函式(heuristic function) h(n)

計算從節點n到目標節點之間所形成路徑的最小代價值。這裡將兩點之間的直線距離作為啟發函式。

辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。醫師把他帶到乙個到處都是草藥的山洞裡對他說:「孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裡,你可以採到一些草藥。如果你是乙個聰明的孩子,你應該可以讓採到的草藥的總價值最大。」

如果你是辰辰,你能完成這個任務嗎?

輸入格式

第一行有 22 個整數 tt(1 \le t \le 10001≤t≤1000)和 mm(1 \le m \le 1001≤m≤100),用乙個空格隔開,tt 代表總共能夠用來採藥的時間,mm 代表山洞裡的草藥的數目。

接下來的 mm 行每行包括兩個在 11 到 100100 之間(包括 11 和 100100)的整數,分別表示採摘某株草藥的時間和這株草藥的價值。

輸出格式

輸出在規定的時間內可以採到的草藥的最大總價值。

?分析我們寫乙個估價函式f ,可以剪掉所有無效的0 枝條(就是剪去大量無用不選枝條)。

估價函式f的執行過程如下:

我們在取的時候判斷一下是不是超過了規定體積(可行性剪枝)。

在不取的時候判斷一下不取這個時,剩下的藥所有的價值 + 現有的價值是否大於目前找到的最優解(最優性剪枝)。

c++

#include #include using namespace std;

const int n = 105;

int n, m, ans;

struct node node[n];

bool operator<(node p, node q)

int f(int t, int v) else

return (int)(tot + v * node[t + i].f);

return tot;

}void work(int t, int p, int v)

int main()

sort(node + 1, node + n + 1);

work(1, m, 0);

printf("%d\n", ans);

return 0;

}

評價函式f(n)=啟發函式h(n)

定義評價函式:f(n)= g(n)+ h(n)

評估函式 = 當前最小開銷代價 + 後續最小開銷代價
為了保證a*演算法是最優(optimal),需要啟發函式h(n)是可容的(admissibleheuristic)和一致的(consistency,或者也稱單調性,即monotonicity)

最優不存在另外乙個解法能得到比a*演算法所求得解法具有更小開銷代價。

可容(admissible)

專門針對啟發函式而言,即啟發函式不會過高估計(over-estimate)從節點n到目標結點之間的實際開銷代價(即小於等於實際開銷)。如可將兩點之間的直線距離作為啟發函式,從而保證其可容。

一致性(單調性)

假設節點n的後續節點是n』,則從n到目標節點之間的開銷代價一定小於從n到n』的開銷再加上從n』到目標節點之間的開銷,即h(n)≤c(n,a, n』)+ h(n』)。這裡n』是n經過行動a所抵達的後續節點,c(n, a,n』)指n』和n之間的開銷代價。

其實…… h = 0時就是 dfs演算法, 並且h = 0邊權為 1時就是 bfs

例如:起始位置是a,目標位置是p,字母後的數字表示節點的估價值

搜尋過程中設定兩個表:open和closed。open表儲存了所有已生成而未考察的節點,closed表中記錄已訪問過的節點。演算法中有一步是根據估價函式重排open表。這樣迴圈中的每一步只考慮open表中狀態最好的節點。具體搜尋過程如下:

初始狀態:                

open=[a5];closed=;

2)估算a5,取得搜有子節點,並放入open表中;

open=[b4,c4,d6];closed=[a5]

3)估算b4,取得搜有子節點,並放入open表中;

open=[c4,e5,f5,d6];closed=[b4,a5]

4)估算c4;取得搜有子節點,並放入open表中;

open=[h3,g4,e5,f5,d6];closed=[c4,b4,a5]

5)估算h3,取得搜有子節點,並放入open表中;

open=[o2,p3,g4,e5,f5,d6];closed=[h3,c4,b4,a5]

6)估算o2,取得搜有子節點,並放入open表中;

open=[p3,g4,e5,f5,d6];closed=[o2,h3,c4,b4,a5]

7)估算p3,已得到解;

看一下偽**

best_first_search()

for(每乙個x的子節點y)

//還沒有排序

else

if(y在open表中)

else

//y在close表中

}    將x節點插入close表中;

按照估價值將open表中的節點排序;

}//end for

}//end while

}//end func

?經典例子:八數碼(我也不懂。。)

在 3 x3的棋盤上,擺有八個棋子,每個棋子上標有 1至8 的某一數字。棋盤中留有乙個空格,空格用 0來表示。空格周圍的棋子可以移到空格中,這樣原來的位置就會變成空格。給出一種初始布局和目標布局(為了使題目簡單,設目標狀態如下),找到一種從初始布局到目標布局最少步驟的移動方法。

123

804765

h 函式可以定義為,不在應該在的位置的數字個數。

容易發現h 滿足以上兩個性質,此題可以使用 a*演算法求解。

#include #include #include #include #include using namespace std;

const int dx[4] = , dy[4] = ;

int fx, fy;

char ch;

struct matrix

} f, st;

int h(matrix a)

struct node

} x;

priority_queueq;

sets;

int main()

q.push();

while (!q.empty())

for (int i = 1; i <= 3; i++)

for (int j = 1; j <= 3; j++)

if (!x.a.a[i][j]) fx = i, fy = j;

for (int i = 0; i < 4; i++) );

swap(x.a.a[fx][fy], x.a.a[xx][yy]);}}

} return 0;

}

前端演算法系列 搜尋

遍歷陣列,找到跟目標相等的元素,就返回它的下標,遍歷結束後,沒找到就返回 1 時間複雜度 o n 迴圈 array.prototype.sequentialsearch function item return 1 const arr 5 4,3 2,1 arr.sequentialsearch 3...

滲透神器系列 搜尋引擎

搜尋引擎是我日常工作中用得最多的一款工具,國內常用的搜尋引擎包括baidu,sougou,bing等。但我本篇要紀錄的並不是這些常用的搜尋引擎,而是資訊保安從業人員必備的幾款網路搜尋引擎。本篇要介紹的搜尋引擎包括 shodan,censys,鍾馗之眼,google,fofa,dnsdb等。介紹的內容...

享受工作系列 人生演算法 活在套路裡

當下中國最好的生意 這兩張圖之間存在著一種對應關係,標準化的成功對應的標準化的服務,非常符合市場規律,是一套相對完整的正向迴圈體系。這些也傳達了乙個資訊,實現財務自由是有階段的,不是所有人都能到達終極階段,而且即使到了最高端階段,人生未必自由,每個階段都人群都被各種稀缺驅趕著,每個階段的人都有每個階...