《漫畫演算法-小灰的演算法之旅》5.11
假設現在有5座金礦,每座金礦的**儲存量不同,需要參入挖掘的工人人數也不同。要求:參入挖礦的工人的總數是10.每座金礦要麼全挖,要麼不挖,不能派出一半人挖取一般**。要求用程式求出,要想得到盡可能多的**,應該選取那幾座金礦?
金礦內容:400,500,200,300,350
所需人數:5,5,3,4,3
對於每一堆金礦總是存在挖與不挖的問題。
知道了這個,我們現在把焦點放在最後乙個金礦上。
此時問題可以轉化為
1,最後一堆金礦挖的情況下的最優解。
2,最後一堆金礦不挖的情況下的最優解。
相應的我們求得max(350+7人數挖前面四堆金礦的最優解,10人挖前面四堆金礦的最優解)。
這倆個稱為全域性問題的來個最優子結構。
同樣的我們對這倆個問題也可以分別的劃分為倆個最優子結構,這樣問題就1化2,2化4,4化8最終我們這裡需要找到問題的邊界就是關鍵了。
我們把全域性最優解和最優子結構之間的關係,以及問題的邊界。這三者的關係用數學表示式表達的話,就叫作狀態轉移方程了。
假設金礦數量設定為n,工人數量設定為w,金礦的含金量設為vector容器g ,所對應的開採人數設為vector容器p
設f(n,w)為n個金礦下w個工人最優收益函式,那麼狀態轉移方程式如下
1,當工人或者金礦的數量為0時收益為0
f(n,w) = 0 (n == 0或 w== 0)
2,當當前的人數不足以挖當前的金礦時,此時的金礦必不會被選擇。
f(n,w) = f(n-1,w)(n>=1,w3,當當前的人數可以挖去當前金礦的時候,此時的金礦可以選擇挖,也可以選擇不挖
f(n,w) = max(f(n-1,w),f(n-1,w-p[n-1])+g[n-1]);//說明:這裡為n-1的原因時因為陣列下標是從0開始的。
那麼我們不難想到**的編寫,可以使用遞迴來實現
int getmaxvalue(vector&g, vector&p, int w, int n)
if (w < p[n - 1])
return max(getmaxvalue(g, p, w, n - 1), getmaxvalue(g, p, w - p[n - 1], n - 1) + g[n - 1]);
}
但是我們可以通過分析,我們做了過多的重複的步驟時間複雜度為o(2^n),那麼我們有沒有什麼辦法將之前計算的結果儲存下來,捨得我們可以效率提公升呢?
int getmaxvalue(vector&g, vector&p, int w, int n)
else
}} return rst[n][w];
}
此種辦法將時間複雜度降低到了o(nw)大大提高的時間效率。
雖然上面的**在時間複雜度上已經沒有什麼可以優化的了,但是在空間複雜度上還可以將之前的二維換成一維陣列。降低空間複雜度。
int getmaxvalue(vector&g, vector&p, int w, int n)
} }return rst[w];
}
上面的便是書中最終優化的**。
通過這道題的理解,我對動態規劃型別的演算法題目有了初步的認識。
動態規劃 求解金礦問題
題目描述 很久很久以前,有乙個國王擁有5座金礦,每座金礦的 儲量不同,需要參與挖掘的工人人數也不相同。例如 有的金礦儲存量是500kg 需要5個工人來挖 有的金礦儲存量是200kg 需要3個工人來挖 如果參與挖礦的工人總數是10,每座金礦要麼全挖,要麼不挖,不能派出一半人挖取一半的金礦,想要得到盡可...
動態規劃 金礦模型
問題描述 有people個人和 num個金礦,開採 每個金礦都需要i people個人,可以獲得i getgold個金子,並且用過的人不可以重複使用,問從這 num個金礦中最多可以得到多少個金子 輸入輸入第一行有兩個數,第乙個是用來開採金礦的總人數,第二個是總金礦數。輸入檔案的第2至n 1行每行有兩...
動態規劃 挖金礦
有乙個國家發現了5座金礦,每座金礦的 儲量不同,需要參與挖掘的工人數也不同。參與挖礦工人的總數是10人。每座金礦要麼全挖,要麼不挖,不能派出一半人挖取一半金礦。要求用程式求解出,要想得到盡可能多的 應該選擇挖取哪幾座金礦?500金 5人 200 3 300 4 350 3 400 5 總容量 10人...