看完原文回到這裡,其實我覺得很多像我這種c語言剛剛入門的人,只理解到了動態規劃的轉移方程,以原文中的例子為例:
當minenum = 0且people >= peopleneeded[minenum]時 f(people,minenum) = gold[minenum]
當minenum = 0且people < peopleneeded[minenum]時 f(people,minenum) = 0
當minenum != 0時 f(people,minenum) = f(people-peopleneeded[minenum], minenum-1) + gold[minenum]與f(people, minenum-1)中的較大者
其中,前兩個式子對應動態規劃的「邊界」,後乙個式子對應動態規劃的「最優子結構」。
菜鳥的我覺得這個比較容易實現啊,於是有了下面的**:
1int goldget(int people, int
minenum)212
else
1316}17
else
1829
else
3033 n = goldget(people, minenum - 1
);34
35return m >= n ?m : n;36}
37 }
後面的關於時間複雜度和空間複雜度的優化對我像我這種境界的人來說,這個理解有點困難,我就暫且自我安慰一下,告訴自己已經理解了動態規劃,並且把文章最後的金礦問題做了,並且通過了測試資料,全部**如下:
#include #include#define maxnum 500
int peopleneeded[maxnum]; //
peopleneeded[i]表示第i座金礦需要的開採人數
int gold[maxnum]; //
gold[i]表示第i座金礦開採後得到的金子數目
int goldget(int people, int
minenum)
else
}else
else
n = goldget(people, minenum - 1
);
return m >= n ?m : n;
}}int
main()
goldget =goldget(people, goldnum);
printf(
"%d\n
", goldget);
return0;
}
/*01揹包問題
*/#include
#include
#include
int max(int x, int
y)int
main()
for(i = 0; i < n; i ++)
}printf(
"%d\n
", best[m - 1
]);
return0;
}
嗯。。。這裡**貌似要斷了很多,對於前面的輸入輸出大家都看得懂,主要的是最後乙個迴圈,其實這個迴圈也比較好理解,在我貼的第乙個比較low的程式裡面,轉移方程是用遞迴實現的,這裡改成了雙重迴圈,其實是乙個意思。最難理解的是:
best[j] = max(best[j], best[j - need[i]] + value[i]);
為了理解這句話需要一步步的來,將一開始比較low的遞迴搞成雙重迴圈(這裡不是說遞迴比較low,而是說我寫的比較low)
for(i = n- 1; i > 0; i --)}
這裡i > 0是因為i = 0沒有討論的必要,其實嚴格的來說這個迴圈和前面的遞迴並不完全一樣,這裡的時間複雜度更低一些,因為這裡的最高收益是用陣列進行儲存的,對於某次迴圈中計算出了best[x][y]的值後,後面如果還需要用到就不需要再計算了,而之前的遞迴用的是函式,並不能儲存數值,效率更低。
這裡我們可以在複習一下轉移方程,
當i != 0時 bes[i][j] 是 best[i - 1][j - need[i]] + value[i]與best[i - 1][j]中的較大者
這裡我們可以發現best[ai][aj]依賴於best[bi][bj]時,肯定有ai = bi + 1,以及aj >= bj。
舉個簡單的例子,我們求best[5][j]的時候只與best[4][j]和best[4][j - need[5]]有關,對於前面的best[0][k],best[1][k],...best[3][k],其中k = 0,1,...m-1沒有任何關係,那麼我們就沒有必要用那麼複雜的儲存。並且j的取值是從m-1到0,考慮到aj >= bj的規律,計算best[i][j]的時候,best[i-1][j+1,...m-1]已經沒有任何利用價值了,這些空間也是多餘的,怎麼辦呢,其實計算best[i][j - 1]的時候best[i - 1][j]就沒有價值了,那麼我們計算best[i][j]的結果就可以直接存放到best[i - 1][j]的位址上,這樣的話,我們的儲存其實只需要乙個大小為m的一維陣列。並且是best[i][j]覆蓋beat[i - 1][j],所以迴圈的時候i要從0到n-1,
於是迴圈就可以寫成
for(i = 0; i < n; i ++)}
這個就是我們最後的結果。
動態規劃的理解
動態規劃的理解 什麼是動態規劃 動態規劃是一種非常精妙的演算法思想,它沒有固定的寫法,極其靈活,常常需要具體問題具體分析。和之前介紹的大部分演算法不同,一開始就直接討論動態規劃的概念並不是很好的學習方式,反而先接觸一些經典模型會有更好的效果。因此本章主要介紹一些動態規劃的經典模型,並在其中穿插動態規...
理解動態規劃
看了演算法導論上對動態規劃的講解,覺得自己對動態規劃的理解又進了一步,之前在讀到 演算法之道 相關章節時就有這感覺,但是仍然不敢說自己已經完全掌握了動態規劃,只是比以前又透徹了一些,說說自己新的理解,其實就是複述一下演算法導論上的內容而已。裝配線排程問題 乙個產品要經過n道工序,有兩條裝配鏈提供著n...
理解動態規劃
通過了解契波那契數列學習動態規劃 問題 斐波那契數列為1 1 2 3 5 8 13 21 34 寫乙個函式,輸入n,求斐波那契 fibonacci 數列的第n項。遞迴方法 includeusing namespace std int dfs int x int main return a x int...