動態(tài)規(guī)劃——算法


零背零、時間與成果的最佳策略

一個老問題:
有一件物品價值15(W)元沉噩,現(xiàn)在有貨幣價值100元、50元昆禽、20元尚粘、10元择卦、5元、1元郎嫁,每張價值的貨幣張數(shù)不限
請問:如何用最小的貨幣張數(shù)秉继,湊出價值W元?

貪婪策略

這樣一個老生常談的問題泽铛,根據(jù)個人的生活體會尚辑,當(dāng)我們?nèi)】梢匀〉淖畲竺骖~,肯定是能最快的縮短到達W元的張數(shù)盔腔。這種思考方式又稱作貪婪策略杠茬。


15元的貪婪策略

可以看到,當(dāng)W=15時铲觉,W=10+5(兩張)澈蝙,大家完全可以拍著大腿說,兩張撵幽,那肯定是最優(yōu)算法灯荧,畢竟一張的情況已經(jīng)被排除了。如果我們在放大W的值盐杂,當(dāng)W=76時逗载,W=50+20+5+1(四張),可以看到貪婪策略只取當(dāng)前最優(yōu)解的做法链烈,非常優(yōu)秀厉斟,極其有利于快速找到一個可接受的解(有些情況下貪婪策略會導(dǎo)致無解,需要另一種思路的支持强衡,魚之后會說)擦秽。
貪婪策略追求的是局部最優(yōu)解,假設(shè)我們加入另一種貨幣11元,此時當(dāng)W=15時感挥,W=11+1+1+1+1(五張)缩搅,這種就叫撿了西瓜丟了一地芝麻,正如他的名字一樣触幼,這就是貪婪的真實面目硼瓣。甚至說有可能發(fā)生貪婪到最后解決不了問題的情況發(fā)生。不可能所有的問題都能簡單的期望單純的追求局部最優(yōu)解最后的結(jié)果也是最優(yōu)解置谦。

窮舉策略

15元的窮舉策略

當(dāng)沒有辦法直接找到最優(yōu)解決方案時堂鲤,另一種策略誕生了:窮舉。即算出所有結(jié)果的可能性媒峡,然后記下最優(yōu)解瘟栖。這種方法思路簡單且明確,尤其是計算機發(fā)達的今天丝蹭,如果不追求效率慢宗,建個模型扔給電腦,讓它慢慢窮舉奔穿,只要不是過于復(fù)雜很快也能得到答案镜沽。游魚突然回想起以前做有些選擇題,全部帶入求解贱田,正是窮舉的表現(xiàn)缅茉,凡是可以把選項帶入求解的絕對不會錯,而且若果有多選男摧,也是不會錯過正確答案蔬墩。窮舉給算法墊底了底線,假設(shè)你設(shè)計的算法效率和窮舉一個樣耗拓,為何不用窮舉呢拇颅?


大多數(shù)情況下,我們不可以容忍非最優(yōu)解乔询,甚至是有可能無法求解樟插,似乎窮舉成為了我們唯一的路。但是窮舉的時間復(fù)雜度是我們無法忍受的「偷螅現(xiàn)在來思考一下為什么貪婪策略的大問題的最優(yōu)解無法由小問題的局部最優(yōu)解推導(dǎo)出來黄锤?

一、最優(yōu)子結(jié)構(gòu)

依然是原來的問題:


貨幣問題

假設(shè)我們要湊出的價值W所需要的貨幣張數(shù)是f(w)食拜,當(dāng)我們用貪婪時鸵熟,我們?nèi)〉慕馐莊(w)=1+f(4),f(4)=4负甸。貪婪策略自以為是把f(4)定義成了小問題的最優(yōu)解流强。很明顯在取一張的情況下痹届,我們要考慮的還有如下幾種情況:

三個可能的最優(yōu)解

魚瞬間發(fā)現(xiàn)一個問題:貪婪策略的問題在于當(dāng)最優(yōu)子結(jié)構(gòu)不定時,因為貪婪策略一味的追求最大的11元打月,忽視了他的f(4)并不是最優(yōu)子結(jié)構(gòu)短纵。假設(shè)對于任意的W都有f(w)=n+f(m),當(dāng)n為定值僵控,最小的m對應(yīng)最小的f(m),那么貪婪策略瞬間成為最優(yōu)策略鱼冀。瞬間一個新問題出現(xiàn)了:當(dāng)前的貨幣政策是否符合貪婪策略下即為最優(yōu)解报破?如果不符合那么如何設(shè)計貨幣政策呢?
此時最小的f(m)就成為了最優(yōu)子結(jié)構(gòu)千绪,而n為定值充易,所以f(w)這個大問題也就迎刃而解了。關(guān)鍵點就在于n為定值荸型,這點又有人稱這種現(xiàn)象叫無后繼性盹靴。

二、重疊子問題

遞歸和循環(huán)是最簡單的重疊子問題瑞妇!重疊子問題的關(guān)鍵點就在f(n)可以由f(n-1)求得稿静,當(dāng)然可能并不是簡單的多項式關(guān)系,因為多項式關(guān)系已經(jīng)被前面的遞歸和循環(huán)攔住了辕狰,自然不需要高級的求解技巧改备。
回到最開始的問題,貨幣回歸到100元蔓倍、50元悬钳、20元、10元偶翅、5元默勾、1元,解得價值W的最優(yōu)策略聚谁!

#!/usr/bin/C#
//雖然此貨幣結(jié)構(gòu)已經(jīng)是貪婪策略下的最優(yōu)解了母剥,但還是練習(xí)一下,畢竟這個算簡單的
//這個方法是前面解析子結(jié)構(gòu)而得到的垦巴,與網(wǎng)上流行的方法有些不太一樣媳搪。
using System;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("目前的貨幣政策,請用逗號隔開骤宣、統(tǒng)一單位秦爆、只要數(shù)字");
            string lines = Console.ReadLine();
            string [] line = lines.Split(',');
            int[] money = new int[line.Length];
            Array.Sort(money);
            for (int i = 0;i< line.Length; i++)
            {
                money[i] = int.Parse(line[i]);
            }
            Console.WriteLine("目前需要湊到的金額數(shù)");
            int aim = int.Parse(Console.ReadLine());
            int[] dp = new int[aim+1];//用來記錄dp下角標所標識的金額最小解。
            int cost;
            for(int m = 1; m <= money[0]; m++) dp[m] = money[money.Length-1];//這邊屬于無法湊出的金額憔披。所以當(dāng)dp的值大于等于max(money[])時說明此金額無法湊出等限。
            for (int i= money[0]; i<= aim;i++)//從最小的可湊金額min(money[])開始計算每個金額的最小解爸吮。
            {
                cost = int.MaxValue;
                for(int j = 0;j< money.Length; j++)//這里的思路就是:因為是從最小的可湊金額開始的min(f(m)) = 1+min(f(m-money[])),其中min(f(m-money[]))在前面循環(huán)已經(jīng)求得解或者是無解,那么自然min(f(m))也就無解或者就是min(f(m-money[]))+1
                {
                    if (i >= money[j]) cost = min(cost, dp[i- money[j]] +1);
                }
                dp[i] = cost;
            }
            
//此時dp的下角標就是對應(yīng)金額的解望门,這里沒高興輸出形娇。
            Console.ReadLine();
        }
        static int min(int a,int b)//取最小值
        {
            return a > b ? b : a;
        }
    }
}

我們來回顧下此處的邏輯:
首先金錢的面額被我們存到數(shù)組money[]里面了,其次我們定義dp[i]=0,i=0(dp表示解)筹误,當(dāng)0<i<min(money[])定義無解桐早。然后我們根據(jù)f(w)=n+f(m)就可以逐步求解:即f[w]=1+min[f(m-money[?])]。最后就可以得到f(w),w=W的值了厨剪。

動態(tài)規(guī)劃入門杰作:背包問題

(這里只介紹下01背包問題哄酝,如果大家還有興趣以下有個網(wǎng)站可以學(xué)習(xí)思路,更加復(fù)雜的思路)
詳詢動態(tài)思考的藝術(shù)

經(jīng)典的背包問題

前面的貨幣問題讓俺們知道了祷膳,用動態(tài)規(guī)劃解決問題就是要優(yōu)化出諸如f(w)=n+f(m)的形式(即找出問題的子結(jié)構(gòu))陶衅,然后才是想怎么解得f(m)的最優(yōu)解。那么如何化解出最優(yōu)子結(jié)構(gòu)直晨?


最優(yōu)子結(jié)構(gòu)

記得前面的貨幣問題嗎搀军?魚來重復(fù)一下,就是不是就呼之欲出呢勇皇?(其實這就是個不一定要湊滿的貨幣問題只不過衡量標準不同導(dǎo)致構(gòu)造子問題的方法不同)
初步解法:
等價轉(zhuǎn)化:前i個物品放到體積為v的背包當(dāng)中=max((前i-1個物品放入體積為v的背包當(dāng)中),(前i-1個物品放入體積為(v-第i件物品的體積)的背包當(dāng)中+第i件物品的價值))


情況詳解

復(fù)習(xí)一下前面的:
n個貨幣湊出價值w = 1 + min(n-1張貨幣湊出價值w-剔除的那張貨幣的價值)

魚只能說罩句,多多接觸,一定能摸索出盲湊最優(yōu)子結(jié)構(gòu)的能力儒士。

#!/usr/bin/C#

            int W =15;
            int[] w = { 5, 4, 7, 2, 6 };
            int[] v = { 5, 3, 10, 3, 7 };
            int[,] dp = new int[v.Length+1,W+1];
            for (int i = 1; i <= v.Length; i++)
            {
                for (int j = 0; j <= W; j++)
                {
                    if (j < w[i-1]) dp[i,j] = dp[i - 1,j];
                    else dp[i,j] = max(dp[i - 1,j], dp[i - 1,j - w[i-1]] + v[i-1]);
                }
            }

優(yōu)化解法:
第一個方法在估算價值時的止,緯度涉及到了物品數(shù)量和體積,時空復(fù)雜度為o(VI)着撩,難道不可以像貨幣問題一樣降低復(fù)雜度嗎诅福?比如只用一維數(shù)組記錄每個V對應(yīng)的最優(yōu)解?
基本可以確認方法肯定是f[v]=max{f[v],f[v-c[i]]+w[i]}

#!/usr/bin/python
w=(5,4,7,2,6)
v=(5,3,10,3,7)
W = 15
dp = [0 for i in range(W+1)]
#初始化空間
for i in range(1,len(w)+1):#取一件物品到取i件物品
    for j in range(len(dp)-1,w[i-1]-1,-1):#對應(yīng)v的最大價值
#為何此處v要倒序拖叙?因為我們求解求的是max((前i-1個物品放入體積為v的背包當(dāng)中),(前i-1個物品放入體積為(v-第i件物品的體積)的背包當(dāng)中+第i件物品的價值))氓润,想一下如果不倒序,此時應(yīng)該是max((前i-1個物品放入體積為v的背包當(dāng)中),(前i個物品放入體積為(v-第i件物品的體積)的背包當(dāng)中+第i件物品的價值))薯鳍,因為因為正序咖气,(v-第i件物品的體積)的實際內(nèi)容已經(jīng)不是(前i-1個物品放入體積為(v-第i件物品的體積)的背包當(dāng)中+第i件物品的價值))了
        dp[j] = max(dp[j], dp[j - w[i-1]] + v[i-1])
print(dp)

如此帶入動態(tài)規(guī)劃的思想。前路漫漫

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挖滤,一起剝皮案震驚了整個濱河市崩溪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌斩松,老刑警劉巖伶唯,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惧盹,居然都是意外死亡乳幸,警方通過查閱死者的電腦和手機瞪讼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粹断,“玉大人符欠,你說我怎么就攤上這事∑柯瘢” “怎么了希柿?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長养筒。 經(jīng)常有香客問我狡汉,道長,這世上最難降的妖魔是什么闽颇? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮寄锐,結(jié)果婚禮上兵多,老公的妹妹穿的比我還像新娘。我一直安慰自己橄仆,他們只是感情好剩膘,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盆顾,像睡著了一般怠褐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上您宪,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天奈懒,我揣著相機與錄音,去河邊找鬼宪巨。 笑死磷杏,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捏卓。 我是一名探鬼主播极祸,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怠晴!你這毒婦竟也來了遥金?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蒜田,失蹤者是張志新(化名)和其女友劉穎稿械,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體物邑,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡溜哮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年滔金,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茂嗓。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡餐茵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出述吸,到底是詐尸還是另有隱情忿族,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布蝌矛,位于F島的核電站道批,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏入撒。R本人自食惡果不足惜隆豹,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茅逮。 院中可真熱鬧璃赡,春花似錦、人聲如沸献雅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挺身。三九已至侯谁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間章钾,已是汗流浹背墙贱。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贱傀,地道東北人嫩痰。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像窍箍,于是被迫代替她去往敵國和親串纺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容