小灰算法--如何求解金礦問題

       題目:
       很久很久之前,有一個人擁有5座金礦,每座金礦的黃金儲量不同,需要參與挖掘的人數也不同,例如有的黃金儲量是500KG黃金,需要5個工人挖掘,(200kg/3人,300kg/4人,350kg/3人,400kg/5人,500kg/5人)
       如果參與挖礦的總數爲10,每座金礦要麼全挖,要麼不挖,用程序求出,應該挖取那幾座金礦。
       
       
       
       到了現在自己好好思考一下自己的思路。。。
       
       
       
       
       解題思路:(典型的動態規劃,和揹包問題類似)
       先假設最後一個金礦註定不會被挖掘
       然後其餘的金礦依次類推,當工人或者金礦爲0 的時候就是問題的邊界。具體如下圖:
在這裏插入圖片描述
       將金礦數量設爲n,工人數量設爲w,金礦的含金量設爲g[],金礦所需開採人數爲數組p[],設F(n,w)爲n個金礦,w個工人的最優收益函數
       轉換方程如下F(n,w) = 0(n=0或w=0)問題邊界爲金礦數爲0或者工人爲0,
       當所剩工人不夠挖掘的時候,只有一種最優子結構
       f(n,w) = F(n-1,w)(n>=1,w<p[n-1])
       在常規情況下,具有兩種最優子結構(挖當前金庫或不挖當前金庫)
       F(n,w) = max(F(n-1,w),F(n-1,w-p[n-1])+g[n-1])(n>=1,w>=p[n-1]),
       代碼如下:

public class getBestGoldMining {
    public static int getBestGoldMining(int w,int n,int[] p,int[] g){
        if(w == 0 || n == 0){
            return 0;
        }
        if(w<p[n-1]){
            return getBestGoldMining(w,n-1,p,g);
        }
        return Math.max(getBestGoldMining(w,n-1,p,g),getBestGoldMining(w-p[n-1],n-1,p,g) +g[n-1]);
    }

    public static void main(String[] args){
        int w = 10;
        int[] p = {5,5,3,4,3};
        int[] g = {400,500,200,300,350};
        System.out.println("最優收益"+getBestGoldMining(w,g.length,p,g));
    }
}

       以上算法雖然可以求解出最優解,但是時間複雜度太高爲O(2^n)。用debug模式就可以看出許多方法調用是重複的,因此,我們應該避免這些重複調用。
       這就要了解動態規劃中的自底而上求解。
       最後程序只需要保存一行數據,從右向左統計,把舊的數據一個一個的替換掉。
//通過二維數組列表計算。
在這裏插入圖片描述
代碼如下:時間複雜度爲o(n)

public static int getBestGoldMiningV3(int w,int[] p,int[] g){
        int[] results = new int[w+1];
        for(int i=1;i<=g.length;i++){
            for(int j = w;j>=1;j--){
                if(j >= p[i-1]){
                    results[j] = Math.max(results[j],results[j-p[i-1]]+g[i-1]);
                }
            }
        }
        return results[w];
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章