演算法思路
① 哪位高手能提供一個撲克牌算24點的演算法思路
我們來看看「算24點」的游戲規則:一副牌中抽去大小王剩下了52張,其中J、Q、K可以當成是11、12、13,也可以都當成1。任意抽取4張牌,用加、減、乘、除(可加括弧)把牌面上的數算成24。每張牌必須用一次且只能用一次。誰先算出來,四張牌就歸誰,如果無解就各自收回自己的牌,哪一方把所有的牌都贏到手中,就獲勝了。
02
一般情況下,先要看4張牌中是否有2,3,4,6,8,Q ,如果有,考慮用乘法,將剩餘的3個數湊成對應數。如果已有兩個6,剩下的只要能湊成3,4,5都能算出24,已有兩個8,剩下的只要能湊成2,3,4,已有兩個Q,剩下的只要能湊成1,2,3都能算出24,比如(9,J,Q,Q)。如果沒有2,3,4,6,8,Q,看是否能先把兩個數湊成其中之一。
② 演算法是解決問題的思路,確定演算法以後可以通過什麼什麼什麼或什麼來描述。
1、演算法就是解決問題的【方法】和【步驟】.
2、演算法描述可以有多種表達方法,一般用【自然語言】【流程圖】和【偽代碼】描述.
3、【偽代碼(Pseudocode)】是介於自然語言和計算機程序語言之間的一種演算法描述.它也是專業軟體開發人員描述演算法的一種常用方法.
4、【演算法】是程序設計的「靈魂」,世界著名計算機科學家【尼克勞斯沃思(NWirth)】指出:【演算法】 + 數據結構=程序.
5、程序設計語言的發展經歷了機器語言、匯編語言到【高級語言】的過程.其中計算機可以直接識別的是【機器語言】,它是由【一串由「0」和「1」構成的二進制】代碼.
望採納.
③ GBDT演算法
對於AdaBoost,可以將其視為一個將多個弱分類器線性組合後對數據進行預測的演算法,該模型可以表示為:
為基函數(即單個弱分類器), 為基函數的參數(即弱分類器中特徵的權重向量), 為基函數的系數(即弱分類器在線性組合時的權重), 就是基函數的線性組合。
給定訓練數據和損失函數 的條件下,構建最優加法模型 的問題等價於損失函數最小化:
這個公式展現了AdaBoost演算法的核心過程。
我們可以利用前向分布演算法來求解上一個式子的最優參數。前向分布演算法的核心是 從前向後,每一步計算一個基函數及其系數,逐步逼近優化目標函數式 ,就可以簡化優化的復雜度。
M-1個基函數的加法模型為:
M個基函數的加法模型:
由上面兩式得:
由這個公式和公式(2)得極小化損失函數:
演算法思路如下:
1. 初始化
2. 對m=1,2,...,M:
a. 極小化損失函數: 得到參數
b. 更新:
3. 得到加法模型:
這樣,前向分布演算法將同時求解從m=1到M所有參數 的優化問題化簡為逐次求解各個 的優化問題。
Freidman提出了梯度提升演算法,演算法的核心是利用損失函數的負梯度將當前模型的值作為回歸問題提升樹演算法中的殘差的近似值,去擬合一個回歸樹。
GBDT的思想就是不斷去擬合殘差,使殘差不斷減少。用一個通俗的例子來講假如有個人30歲,我們首先用20歲去擬合,發現損失有10歲,這時我們用6歲去擬合剩下的損失,發現差距還有4歲,第三輪我們用3歲擬合剩下的差距,差距就只有一歲了。如果我們的迭代輪數還沒有完,可以繼續迭代下面,每一輪迭代,擬合的歲數誤差都會減小。(參考 集成學習之Boosting-gbdt )GBDT中每次迭代構造的Cart樹都是用前一輪的殘差擬合的。
第t輪第i個樣本的損失函數的負梯度表示為:
利用 我們可以擬合一顆CART回歸樹,得到了第t顆回歸樹,其對應的葉節點區域 其中J為葉子節點個數。
針對每一個葉子節點里的樣本,我們求出使損失函數最小的 輸出值 :
這樣我們就得到了本輪的決策樹擬合函數:
從而本輪最終得到的強學習器的表達式如下:
通過損失函數的負梯度來擬合,是一種通用的擬合損失誤差的辦法。無論是分類問題還是回歸問題,我們都可以通過其損失函數的負梯度的擬合,從而用GBDT來解決我們的分類和回歸問題。區別僅僅在於損失函數不同導致的負梯度不同而已。
d. 分位數損失:它對應的是分位數回歸的損失函數。
輸入: 訓練樣本
迭代次數(基學習器數量): T
損失函數: L
輸出: 強學習器H(x)
演算法流程
對於二元GBDT,其對數損失函數在之前已經給出:
其中 此時的負梯度誤差為:
對於生成的決策樹,各個葉子節點的最佳負梯度擬合值為:
由於這個式子不易優化,一般使用近似值代替:
除了負梯度計算和葉子節點的最佳負梯度擬合的線性搜索,二分類GBDT與GBDT回歸演算法過程相同。
多分類GBDT的損失函數在之前也已經給出過:
樣本屬於第k類的概率 的表達式為:
結合上面兩個式子可以求出第t輪第i個樣本對應類別 l 的負梯度誤差為:
可以看出,其實這里的誤差就是樣本i對應類別l的真實概率和t-1輪預測概率的差值。
對於生成的決策樹,各個葉子節點的最佳負梯度擬合值為:
由於上式比較難優化,一般用近似值代替:
除了負梯度計算和葉子節點的最佳負梯度擬合的線性搜索,多分類GBDT與二分類GBDT以及GBDT回歸演算法過程相同。
為了防止GBDT過擬合,需要對其進行正則化。主要有三種方式:
1. 給每棵樹的輸出結果乘上一個步長(學習率) a 。之前的弱學習器的迭代式改為:
2. 通過子采樣比例進行正則化。GBDT每一輪建樹時樣本從原始訓練集中採用無放回隨機抽樣的方式產生。若采樣比例取1,則採用全部樣本進行訓練。為了防止過擬合,同時又要防止樣本擬合偏差較大(欠擬合),要合理取值,常用 [0.5, 0.8]
3. 對弱學習器(CART)進行正則化剪枝:控制樹的最大深度、節點最少樣本數、最大葉子節點數、節點分支的最小樣本數等。
優點 :
缺點 :
由於弱學習器之間存在依賴關系,難以並行訓練數據
boosting框架相關參數 :
弱學習器參數 :
GBDT的適用面非常廣,幾乎可以用於所有回歸問題(線性/非線性),也可以用於分類問題。
④ 請教高人 遞歸演算法編寫思路技巧
一個子程序(過程或函數)的定義中又直接或間接地調用該子程序本身,稱為遞歸。遞歸是一種非常有用的程序設計方法。用遞歸演算法編寫的程序結構清晰,具有很好的可讀性。遞歸演算法的基本思想是:把規模大的、較難解決的問題變成規模較小的、易解決的同一問題。規模較小的問題又變成規模更小的問題,並且小到一定程度可以直接得出它的解,從而得到原來問題的解。
利用遞歸演算法解題,首先要對問題的以下三個方面進行分析:
一、決定問題規模的參數。需要用遞歸演算法解決的問題,其規模通常都是比較大的,在問題中決定規模大小(或問題復雜程度)的量有哪些?把它們找出來。
二、問題的邊界條件及邊界值。在什麼情況下可以直接得出問題的解?這就是問題的邊界條件及邊界值。
三、解決問題的通式。把規模大的、較難解決的問題變成規模較小、易解決的同一問題,需要通過哪些步驟或等式來實現?這是解決遞歸問題的難點。把這些步驟或等式確定下來。
把以上三個方面分析好之後,就可以在子程序中定義遞歸調用。其一般格式為:
if 邊界條件 1 成立 then
賦予邊界值 1
【 elseif 邊界條件 2 成立 then
賦予邊界值 2
┇ 】
else
調用解決問題的通式
endif
例 1 : 計算勒讓德多項式的值
x 、 n 由鍵盤輸入。
分析: 當 n = 0 或 n = 1 時,多項式的值都可以直接求出來,只是當 n > 1 時,才使問題變得復雜,決定問題復雜程度的參數是 n 。根據題目提供的已知條件,我們也很容易發現,問題的邊界條件及邊界值有兩個,分別是:當 n = 0 時 P n (x) = 1 和當 n = 1 時 P n (x) = x 。解決問題的通式是:
P n (x) = ((2n - 1)P n - 1 (x) - (n - 1)P n - 2 (x)) / n 。
接下來按照上面介紹的一般格式定義遞歸子程序。
function Pnx(n as integer)
if n = 0 then
Pnx = 1
elseif n = 1 then
Pnx = x
else
Pnx = ((2*n - 1)*Pnx(n - 1) - (n - 1)*Pnx(n - 2)) / n
endif
end function
例 2 : Hanoi 塔問題:傳說印度教的主神梵天創造世界時,在印度北部佛教聖地貝拿勒斯聖廟里,安放了一塊黃銅板,板上插著三根寶石針,在其中一根寶石針上,自下而上地放著由大到小的 64 個金盤。這就是所謂的梵塔( Hanoi ),如圖。梵天要求僧侶們堅持不渝地按下面的規則把 64 個盤子移到另一根針上:
(1) 一次只能移一個盤子;
(2) 盤子只許在三根針上存放;
(3) 永遠不許大盤壓小盤。
梵天宣稱,當把他創造世界之時所安放的 64 個盤子全部移到另一根針上時,世界將在一聲霹靂聲中毀滅。那時,他的虔誠的信徒都可以升天。
要求設計一個程序輸出盤子的移動過程。
分析: 為了使問題更具有普遍性,設共有 n 個金盤,並且將金盤由小到大依次編號為 1 , 2 ,…, n 。要把放在 s(source) 針上的 n 個金盤移到目的針 o(objective) 上,當只有一個金盤,即 n = 1 時,問題是比較簡單的,只要將編號為 1 的金盤從 s 針上直接移至 o 針上即可。可定義過程 move(s,1,o) 來實現。只是當 n>1 時,才使問題變得復雜。決定問題規模的參數是金盤的個數 n ;問題的邊界條件及邊界值是:當 n = 1 時, move(s,1,o) 。
當金盤不止一個時,可以把最上面的 n - 1 個金盤看作一個整體。這樣 n 個金盤就分成了兩個部分:上面 n - 1 個金盤和最下面的編號為 n 的金盤。移動金盤的問題就可以分成下面三個子問題(三個步驟):
(1) 藉助 o 針,將 n - 1 個金盤(依照上述法則)從 s 針移至 i(indirect) 針上;
(2) 將編號為 n 的金盤直接從 s 針移至 o 針上;
(3) 藉助 s 針,將 i 針上的 n - 1 個金盤(依照上述法則)移至 o 針上。如圖
其中第二步只移動一個金盤,很容易解決。第一、第三步雖然不能直接解決,但我們已經把移動 n 個金盤的問題變成了移動 n - 1 個金盤的問題,問題的規模變小了。如果再把第一、第三步分別分成類似的三個子問題,移動 n - 1 個金盤的問題還可以變成移動 n - 2 個金盤的問題,同樣可變成移動 n - 3 ,…, 1 個金盤的問題,從而將整個問題加以解決。
這三個步驟就是解決問題的通式,可以以過程的形式把它們定義下來:
hanoi(n - 1,s,o,i)
move(s,n,o)
hanoi(n - 1,i,s,o)
參考程序如下:
declare sub hanoi(n,s,i,o)
declare sub move(s,n,o)
input "How many disks?",n
s = 1
i = 2
o = 3
call hanoi(n,s,i,o)
end
sub hanoi(n,s,i,o)
rem 遞歸子程序
if n = 1 then
call move(s,1,o)
else
call hanoi(n - 1,s,o,i)
call move(s,n,o)
call hanoi(n - 1,i,s,o)
endif
end sub
sub move(s,n,o)
print "move disk";n;
print "from";s;"to";o
end sub
⑤ 求一個最優路徑演算法的思路
同意樓上,最長路徑是NPC問題,不存在多項式演算法。
證明是簡單的:
1、最長無環路問題的判定版本是「給定有向圖D和整數k,問D中是否存在長度大於或等於k的無環路」(這一表述對有權圖和無權圖都有效)。
2、將Hamilton路問題規約到最長無環路問題(的判定版本)是顯然的:輸入一個n頂點的有向圖D,直接問:有向圖D中是否存在長度大於等於n-1的無環路?
簡言之,對任意n頂點的有向圖D,假如能夠D中的找到最長無環路P,那麼就能立即知道D中是否存在Hamilton路(只需看P的長度是否為n-1即可),從而最長無環路問題是NPC。
小規模就直接DFS吧。大規模的時候DFS剪枝。不過確實不好做呀。
有向無圈圖的話可以用dijstra貪心,或者簡單用folyed演算法就可以了(把最小化變為最大化)。
有圈的話您……或者能縮圈么?可以考慮。總之比較復雜。
⑥ 禁忌搜索演算法的主要思路
1、在搜索中,構造一個短期循環記憶表-禁忌表,禁忌表中存放剛剛進行過的 |T|(T稱為禁忌表)個鄰居的移動,這種移動即解的簡單變化。
2、禁忌表中的移動稱為禁忌移動。對於進入禁忌表中的移動, 在以後的 |T| 次循環內是禁止的,以避免回到原來的解,從而避免陷入循環。|T| 次循環後禁忌解除。
3、禁忌表是一個循環表,在搜索過程中被循環的修改,使禁忌表始終保持 |T| 個移動。
4、即使引入了禁忌表,禁忌搜索仍可能出現循環。因此,必須給定停止准則以避免出現循環。當迭代內所發現的最好解無法改進或無法離開它時,演算法停止。