A 演算法在OI中的應用

2021-12-30 01:19:57 字數 1909 閱讀 2275

1.a*演算法

我們普通的搜尋演算法往往複雜度都是指數級,oi中這樣的複雜度無法滿足我們的要求。這時我們一般都會進行一些剪枝優化,但在有些題目中卻可以有更加巧妙的方法——a*演算法。

a*演算法作為一種基礎的啟發式搜尋,它不同於dfs和bfs將所有情況進行遍歷,它能從所有情況中選出較優的再進行遍歷。因此,它讓搜尋從「瞎搜」轉化到了「有目標的搜尋」。那麼如何確定較優的情況便是關鍵所在。

a*演算法中核心是乙個估值函式,我們可以通過它來得到每種情況的優劣。用公式表示便是:

f(n)=g(n)+h(n)

當中g(n)是從初始狀態到當前狀態是實際代價,可以通過計算得出,h(n)便是估值函式,估計當前狀態到結束狀態的代價,f(n)便是估計出來的總代價。由此我們將每乙個狀態估價,我們便可以選出f(n)更優的狀態進行遍歷。不難看出,這個估值函式可以有不同的選擇,同時也直接影響到了演算法的效率,因此這個函式的選取是極為重要的。

2.h(n)的選取

下面所說的h(n)即為估值函式,d(n)為實際值(當前狀態到結束狀態的實際代價)

如果h(n)

如果h(n)=d(n),估算代價等於實際值,估計結果等於實際結果,因此搜尋按照實際的最優情況經行,效率最高。

如果h(n)>d(n),估算代價大於實際值,估計結果更優的較少,因此搜尋的範圍更小,效率高,但是不一定得出最優解。

在oi中,為了保證答案最優,我們往往選擇h(n)$

我們看兩個例子:

第乙個是scoi2005 騎士精神(bzoj 1085),這道題目似乎沒有其他的技巧,只能進行搜尋,資料範圍也確實不大。但是普通的搜尋肯定會超時的,於是很自然的想到了a*演算法。這道題中h(n)不難想出,就是當前狀態有多少個需要移動的騎士。雖然有可能h(n)較小實際值卻偏大,但我們這裡是偏優的估計,即是h(n)$

int h()

return sum;

}第二個是比較有名的八數碼問題(不清楚的可以百度一下),這道題一般容易想到搜尋。這道題目h(n)選取有兩種方法,第一種便是同上一題相似,h(n)是有多少個數字需要移動。但還有一種更為巧妙(當然也更精確)的選取方式:便是每乙個數字到目標位置的曼哈頓距離(就是到目標位置要走多少個格仔)之和。不難看出,這樣的估計也是偏優的。估值函式**如下:

const int aimx[9]=,aimy[9]=;

//aimx[i]表示目標狀態數字i的縱座標,aimy表示橫座標

int h()

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

sum+=abs(nx[i]-aimx[i])+abs(ny[i]-aimy[i]); //到目標位置曼哈頓距離

return sum;

}現在我們對估值函式的選取有了一定的了解,寫題時靈活準確的選取h(n)是關鍵。

3.ida*演算法

a* 演算法在實現過程中往往是在獲得的子節點中選取f(n)最小的子節點進行擴充套件(一般用堆或優先佇列選出f(n)最小的子節點),通過維護關閉列表和開放列表,對擴充套件出來的節點進行檢測(判重,為提高效率有時使用hash)。詳細的實現步驟可以參考其他部落格,這裡偏向於思想和應用層面。我們可以看出,普通a*將大部分時間消耗在了將f(n)排序和情況判重上,同時類似於bfs將狀態儲存到節點中,這也往往需要很大的空間。

而ida* 綜合了a* 演算法和迭代加深搜尋(一種dfs),有著空間消耗少的特點。同時不需要儲存節點,也不用將狀態排序和判重,在時間和空間上都優於普通的a* 演算法。它是在f(n)>預定的最大搜尋深度時進行剪枝。這樣的**難度往往會小很多,在oi中ida* 演算法比a* 演算法實用很多。

舉個例子,還是上一題的八數碼問題,ida*的**就很簡潔:(部分核心**)

void dfs(int x, int y, int g) //g便是公式中g(n)

//h(n)==0時便是與目標狀態完全相同

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

return ;

}for(ans=0; ;ans++)

}

Lru演算法在Android中的應用

對於lru演算法的理解 lru演算法,將命中率不高的空間釋放掉,保留命中率較高的空間。這種演算法有一種實現方式 建立的物件通過佇列儲存起來,如果對乙個物件進行了訪問,就將這個物件放到佇列的開頭,新加入的物件也會放在佇列的開頭 也就是說,佇列開頭一定是新加入的或者是常用的物件 當佇列長度超過了限額時,...

令牌桶演算法在限速中的應用

令牌桶中有初始容量,每來乙個請求從桶中獲取乙個令牌,並且在一定時間間隔中可以生成令牌,多餘的令牌被丟棄。可以實現限速功能。主要針對不同使用者的請求進行限速,如果單獨使用google的ratelimiter可以控制請求的速率,如果超過限定的速率則進行等待,但是無法獲取使用者的請求速率。如果下可以根據不...

Pid演算法在閉環dc dc中的應用

part1 專案簡述 第一,專案內容與試驗目的。專案內容 搭建硬體buck平台 開環,平台上包括柵極驅動電路 使用fpga完成資料採集和資料處理,設計乙個fpga數控電源。本次設計,採用的adc型號為ad9200。試驗目的 1 在fpga開發平台上成功執行pid演算法 2 熟悉數字設計中的小數處理方...