動態規劃 砝碼稱重問題

2021-07-22 11:33:30 字數 2736 閱讀 5210

動態規劃(dynamic programming)這個詞乍一聽感覺甚是高大上,初次學習或者使用的時候會感覺難以理解,這是正常的,畢竟凡事都是一回生二回熟。其實它也不難的,大家要明白乙個道理,能寫到課本上給學生學習的東西必然屬於不難的東西,因為太難的東西寫到課本上讀者接受不了,這本書就沒有出版的意義了。當然我說的不難也僅僅只是說動態規劃的思想不難,因為我們常常面臨著乙個棘手的問題---那就是這個理論應用到實踐中的時候,它沒有乙個公式或者現成的可以直接用來套用的模型。對於這一點,沒有辦法,只能是通過多種案例,自己多總結,多思考,看看每一種能用動態規劃理論解決的問題,狀態模型究竟是如何建立的,而這就需要讀者多多練習了。

先來讀一讀題目,題目如下:

現有一組砝碼,重量互不相等,分別為m1、m2……mn;他們可取的最大數量分別為x1、x2……xn。現在要用這些砝碼去稱物體的重量,問能稱出多少種不同的重量。

看完這個題目感覺似乎無從下手,難道要乙個個的列舉拼湊嗎?答案是否定的。不繞彎子了,下面直接進入動態規劃的主場。我們假定砝碼的重量單位是克,下文中不新增這個單位,只說數字,比如重量是1,表示重量是1克。

設想第0種情況,假如現在只有0個砝碼,問它能稱出的重量有幾種?是個人都知道只能稱0的重量,並且只有這麼1種情況。

設想第1種情況,現在只有1種規格的砝碼,它的重量是1,數量是1個,問它能稱出的重量有幾種?很明顯,能稱出0和1這2種重量,一共2種情況。

設想第2種情況,現在有2種規格的砝碼,它們的重量分別是1和2,1克的砝碼1個,2克的砝碼1個,問它能稱出的重量有幾種?用手比劃比劃應該能知道,能稱出0,1,2,3這4種重量,4種情況。

設想第n種情況,現在有n種規格的砝碼,他們的重量分別為m1,m2。。。mn,問它能稱出的重量是幾種?這個時候貌似不是用手比劃比劃就可以出來結果了。但是這個問題的提出,就相當於是題目最終要解決的問題了。如果能夠利用某種規律回答這第n種情況的提問,那麼砝碼稱重的問題就可以完全解決。問題來了,上面的分析過程是否存在乙個規律呢?答案是規律肯定存在,並且分析這種規律的思路就是動態規劃的思路。

現在我們把第n種情況能稱出的重量種數用f(n)來表示,可以試著這樣具體化的描述,第0種情況能稱出的重量有f(0)種,第1種情況能稱出的重量有f(1)種,第2種情況能稱出的重量有f(2)種,。。。第n種情況能稱出的重量有f(n)種。

下面,回歸到上面的提到的情況分析中去。

第0種情況,f(0)=1;

第1種情況,f(1)=2;如果把這個結果和第0種情況結合起來看,可以認為:f(1)=f(0)+1,此式意義非凡,它的意義為:第1種情況可以建立在第0種情況的基礎上去解決,單單來看情況1的砝碼可以稱1種重量(即用乙個1克的砝碼稱1克的物體)不同於情況0中,二者相加即為f(1)的結果。

第2種情況,f(2)=4=f(1)+2,為什麼加2?因為如果僅僅只有1個1克的砝碼和1個2克的砝碼,它只能稱出重量為2克,3克這兩種不同於情況1中的重量(情況1中已經解決了0克和1克的問題)。

現在假定已經解決了第n-1種情況,即f(n-1)的值已經知道,那麼我們如果能計算出單單第n種情況能稱出哪些不同於n-1種情況中的重量,假定為x種,那麼f(n)=f(n-1)+x。最終問題便得到了解決。

請仔細領會上面的這個分析過程,一定要弄明白。

下面附上c++的程式,本程式先計算第0種砝碼能稱出多少種重量,能稱出的重量均在flag[100000]陣列中做好標記,然後計算第0種砝碼最多能稱多大的重量,在這個基礎上加入第1種砝碼,然後計算第2種,直至第n種。程式最關鍵的地方在於29行採用currentweight逐次加1試探的方式得到乙個數值,然後在33行驗證這個currentweight是否是前一種情況中的砝碼可以稱出來的重量,如果是,表明新的重量值確實可以稱出來,那麼就把這個重量在flag[100000]陣列中標記。最後統計標誌陣列flag[100000]種1的次數,即為所有砝碼隨意組合可以稱出的重量。

#include #include #include using namespace std;

int fama(int n, int weight, int num)

; /*先計算第0種砝碼能夠得到的稱重數量,並且計算第0種砝碼最大的重量*/

int tempweight = 0;

for (i = 0; i <=num[0]; i++)

tempweight = weight[0]*num[0];

//從此以後tempweight將用來表示前一種砝碼的最大重量

i = 1;//從第1種砝碼開始做

int currentweight;

int newweight;

while (i < n)

}} tempweight = tempweight + num[i] * weight[i];//更新上乙個砝碼的最大重量

i++;

} /*統計總數量*/

int count = 0;

for (i = 0; i < 1000; i++)

return count;

}int main()

{ int n;

cin >> n;

int *w = new int[n];

int *num = new int[n];

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

cin >> w[i];

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

cin >> num[i];

cout <

總結動態規劃的思路就是--總是試圖從最簡單的情況開始著手找出答案,利用最簡單的情況的答案計算下一種情況的答案。存在一種規律使得f(n)=f(n-1)+x的模式,使我們可以利用迴圈體計算n種情況。



動態規劃 砝碼稱重問題

一 演算法分析 動態規劃 dynamic programming 這個詞乍一聽感覺甚是高大上,初次學習或者使用的時候會感覺難以理解,這是正常的,畢竟凡事都是一回生二回熟。其實它也不難的,大家要明白乙個道理,能寫到課本上給學生學習的東西必然屬於不難的東西,因為太難的東西寫到課本上讀者接受不了,這本書就...

動態規劃 砝碼稱重

問題描述 設有1g,2g,3g,5g,10g,20g的砝碼各若干枚 其總重 1000g 要求 輸入 a1 a2 a3 a4 a5 a6 表示1g砝碼有a1個,2g砝碼有a2個,20g砝碼有a6個 輸出 total n n表示用這些砝碼能稱出的不同重量的個數,但不包括乙個砝碼也不用的情況 輸入樣例 1...

動態規劃 砝碼稱重

砝碼稱重問題 設有1g 2g 3g 5g 10g 20g 的砝碼各若干枚 其質量 1000g 求出用他們能稱出的質量的種類數 不包括質量為0的情況 設dp 1000 陣列為標記陣列。當dp 0時,表示質量為i的情況,目前沒有稱出 當dp 1時,表示質量為i的情況已經稱出。本題目中有多個砝碼,我們順序...