1. 程式人生 > >演算法題——Ones and Zeroes(JAVA)動態規劃

演算法題——Ones and Zeroes(JAVA)動態規劃

題目描述:
In the computer world, use restricted resource you have to generate maximum benefit is what we always want to pursue.

For now, suppose you are a dominator of m 0s and n 1s respectively. On the other hand, there is an array with strings consisting of only 0s and 1s.

Now your task is to find the maximum number of strings that you can form with given m 0s and n 1s. Each 0 and 1 can be used at most once.

Note:
The given numbers of 0s and 1s will both not exceed 100
The size of given string array won’t exceed 600.

讀題:
有一定數量的0和1,組成陣列中儘量多的字串。類似於一個二維的揹包問題。

知識儲備:
揹包問題
令V(i,j)表示在前i(1<=i<=n)個物品中能夠裝入容量為就j(1<=j<=C)的揹包中的物品的最大價值,則可以得到如下的動態規劃函式:

(1)   V(i,0)=V(0,j)=0 
(2) V(i,j)=V(i-1,j) ,j < wi
V(i,j)=max{V(i-1,j) ,V(i-1,j-wi)+vi) } ,j>wi

(1)式表明:如果第i個物品的重量大於揹包的容量,則裝人前i個物品得到的最大價值和裝入前i-1個物品得到的最大價是相同的,即物品i不能裝入揹包;
第(2)個式子表明:如果第i個物品的重量小於揹包的容量,則會有一下兩種情況:
(a)如果把第i個物品裝入揹包,則揹包物品的價值等於第i-1個物品裝入容量位j-wi 的揹包中的價值加上第i個物品的價值vi;
(b)如果第i個物品沒有裝入揹包,則揹包中物品價值就等於把前i-1個物品裝入容量為j的揹包中所取得的價值。顯然,取二者中價值最大的作為把前i個物品裝入容量為j的揹包中的最優解。

解題思路:
動態規劃:解決子問題並記錄子問題的解
子問題為:要不要組建這個字串。
在有i個待選字串,原料為m n的情況下揹包問題下:
最優解是什麼?

第i+1個字串可以選擇放進揹包或者不放進揹包?
假設放進揹包(前提是放得下),
那麼f[m][n][i+1]=f[m-weight[i+1]][n-weight[i+1]][i]+1;
如果不放進揹包,
那麼f[m][n][i+1]=f[m][n][i]。
也就是:
f[m][n][i+1]=max(f[m][n][i],f[m-weight[i+1]][n-weight[i+1]][i]+1)。

提交程式碼:

public class Solution {
    private int[][][] dpTable;//儲存狀態結果
    public int findMaxForm(String[] strs, int m, int n) {
        int len = strs.length;
        int arr[][] = new int[len][2]; 
        int res = 0;
        //計算字串中0和1的個數
        for (int i = 0; i < len; i++) {
            char[] chars = strs[i].toCharArray();
            int zero = 0;
            int one = 0;
            for (int j = 0; j < chars.length; j++) {
                if (chars[j] == '1')
                    one++;
                else
                    zero++;
            }
            arr[i][0] = zero;
            arr[i][1] = one;
            arr[i][2] = one+zero;
        }
        dpTable = new int[m+1][n+1][len];
        return FormTable(arr, len, m, n, 0);
    }
    private int FormTable(int[][] arr, int len, int m, int n, int pos) {
        if (m+n == 0 || pos == len) {
            return 0;
        }
        //如果之前已經算過了,則直接取出資料
        if (dpTable[m][n][pos] > 0) {
            return dpTable[m][n][pos];
        }
        int addCount = 0;
        //加入這條字串的情況
        if (m >= arr[pos][0] && n >= arr[pos][1]) {
            addCount = FormTable(arr, len, m-arr[pos][0], n-arr[pos][1], pos+1) + 1;
        }
        //不加入這條字串的情況
        int unaddCount = FormTable(arr, len, m, n, pos+1);
        if (addCount > unaddCount) {
            dpTable[m][n][pos] = addCount;
        } else {
            dpTable[m][n][pos] = unaddCount;
        }
        return dpTable[m][n][pos];
    }
}