(本文參考 OI Wiki )
一、枚舉法
枚舉的思想是不斷地猜測,從可能的集合中一一嘗試形娇,然后再判斷題目的條件是否成立袍啡。
要點:
1)給出解空間:在一定范圍內(nèi),可能發(fā)生的情況是什么勒魔?
2)減少枚舉的空間:目的是減少不必要的開銷
3)選擇合適的枚舉順序:根據(jù)題目要求,選擇最合理的枚舉順序
二、模擬
模擬就是用計算機來模擬題目中要求的操作凛膏。
模擬題目通常具有碼量大、操作多它浅、思路繁復(fù)的特點译柏。
三、遞歸
遞歸姐霍,在數(shù)學(xué)和計算機科學(xué)中是指在函數(shù)的定義中使用函數(shù)自身的方法鄙麦,在計算機科學(xué)中還額外指一種通過重復(fù)將問題分解為同類的子問題而解決問題的方法。
什么是遞歸镊折?
遞歸的基本思想是某個函數(shù)直接或者間接地調(diào)用自身胯府,這樣原問題的求解就轉(zhuǎn)換為了許多性質(zhì)相同但是規(guī)模更小的子問題。求解時只需要關(guān)注如何把原問題劃分成符合條件的子問題恨胚,而不需要過分關(guān)注這個子問題是如何被解決的骂因。
遞歸的例子:
如何給一堆數(shù)字排序?答:分成兩半赃泡,先排左半邊再排右半邊寒波,最后合并就行了乘盼,至于怎么排左邊和右邊,請重新閱讀這句話俄烁。
遞歸代碼最重要的兩個特征:結(jié)束條件和自我調(diào)用绸栅。自我調(diào)用是在解決子問題,而結(jié)束條件定義了最簡子問題的答案页屠。
int func(傳入數(shù)值){
if(終止條件)? return最小子問題解;? //結(jié)束條件
return func(縮小規(guī)模);? //自我調(diào)用
}
為什么要寫遞歸粹胯?
1、遞歸結(jié)構(gòu)清晰辰企,可讀性強风纠。
2、使用遞歸能練習(xí)分析問題的結(jié)構(gòu)牢贸。當(dāng)發(fā)現(xiàn)問題可以被分解成相同結(jié)構(gòu)的小問題時竹观,遞歸寫多了就能敏銳發(fā)現(xiàn)這個特點,進(jìn)而高效解決問題十减。
遞歸的缺點:
1)在程序執(zhí)行中栈幸,遞歸是利用堆棧來實現(xiàn)的。每當(dāng)進(jìn)入一個函數(shù)調(diào)用帮辟,棧就會增加一層棧幀速址,每次函數(shù)返回,棧就會減少一層棧幀由驹。而棧不是無限大的芍锚,當(dāng)遞歸層數(shù)過多時,就會造成?棧溢出?的后果蔓榄。
2)顯然有時候遞歸處理是高效的并炮,比如歸并排序;有時候是低效的甥郑,因為堆棧會消耗額外空間逃魄,而簡單的遞推不會消耗空間。
遞歸優(yōu)化:
主頁面:搜索優(yōu)化 和 記憶化搜索
比較初級的遞歸實現(xiàn)可能遞歸次數(shù)太多澜搅,容易超時伍俘。這時需要對遞歸進(jìn)行優(yōu)化。
寫遞歸的要點:
明白一個函數(shù)的作用并相信它能完成這個任務(wù)勉躺,千萬不要跳進(jìn)這個函數(shù)里面企圖探究更多細(xì)節(jié)
四癌瘾、分治
分治算法的核心思想就是“分而治之”。
大概的流程可以分為三步:分解 -> 解決 -> 合并饵溅。
1妨退、分解原問題為結(jié)構(gòu)相同的子問題。
2、分解到某個容易求解的邊界之后咬荷,進(jìn)行遞歸求解冠句。
3、將子問題的解合并成原問題的解萍丐。
分治法能解決的問題一般有如下特征:
1)問題規(guī)模較小:該問題的規(guī)男耍縮小到一定的程度就可以容易地解決。
2)問題可以分解與合并:該問題可以分解為若干個規(guī)模較小的相同問題逝变,即該問題具有最優(yōu)子結(jié)構(gòu)性質(zhì),利用該問題分解出的子問題的解可以合并為該問題的解奋构。
3)分解的子問題是獨立的:該問題所分解出的各個子問題是相互獨立的壳影,即子問題之間不包含公共的子問題。
注意:(如果各子問題是不獨立的弥臼,則分治法要重復(fù)地解公共的子問題宴咧,也就做了許多不必要的工作。此時雖然也可用分治法径缅,但一般用 動態(tài)規(guī)劃??較好掺栅。)
區(qū)別:
遞歸與枚舉:
遞歸和枚舉的區(qū)別在于:枚舉是橫向?地把問題劃分,然后依次求解子問題纳猪;而遞歸是把問題逐級分解氧卧,是縱向?的拆分。
遞歸與分治:
遞歸是一種編程技巧氏堤,一種解決問題的思維方式?沙绝;分治算法很大程度上是基于遞歸的,解決更具體問題的算法思想鼠锈。