动态规划:0-1 背包问题

    0-1背包问题是典型的动态规划问题,需要求解的是,为了体积V的背包中物体总价值最大化,N件物品中第i件应该放入背包中吗?(其中每个物品最多只能放一件)。

    思路:定义一个二维数组f[N][V],其中每个元素代表一个状态,即前i个物体中若干个放入体积为V背包中最大价值。其中f[i][j]表示前i件中若干个物品放入体积为j的背包中的最大价值。 分别对i和j进行循环,从小到大逐步计算,其中,大问题依赖于小问题的求解。

    初始状态:f[0][0...V]和f[0...N][0]都为0,前者不放任何物体,不管背包体积是多少,价值都为0;后者表示背包体积为0,放不来任何物体,价值也肯定都是0。

    转移函数:

    if (背包体积j小于物品i的体积)        f[i][j] = f[i-1][j] //背包装不下第i个物体,目前只能靠前i-1个物体装包

    else     f[i][j] = max(f[i-1][j], f[i-1][j-Vi] + Wi) //不装当前物体,或装当前物体,选价值最大者

    示例代码:

#include<iostream>
using namespace std;

int main()
{
    int nArr[6][13] = {{0}};
    int nCost[6] = {0 , 2 , 5 , 3 , 10 , 4};  //花费
    int nVol[6]   = {0 , 1 , 3 , 2 , 6 , 2}; //物体体积
    int bagV = 12;

    for( int i = 1; i< sizeof(nCost)/sizeof(int); i++)
    {
        for( int j = 1; j<=bagV; j++)
        {
            if(j<nVol[i])
                nArr[i][j] = nArr[i-1][j];
            else
                nArr[i][j] = max(nArr[i-1][j] , nArr[i-1][j-nVol[i]] + nCost[i]);       
            cout<<nArr[i][j]<<' ';
        }   
        cout<<endl;
    }
    cout<<nArr[5][12]<<endl;

    return 0;
}

    循环过程如下图,从左上角开始,一行一行往后,直到右下角


    更深入的,可能会有更多维的问题,如有多个“体积”(即多个限制条件)。如下面的问题:

    给定一个字符串数组,每个字符串由0和1组成,给定两个常数m和n,m表示拥有的0的个数,n表示拥有的1的个数,求用这m个0和n个1,最多可以组成数组中的字符串的最大个数。

    这个问题就有两个限制条件:0的个数和1的个数。不过思路相似,只是多了一重循环。

public int findMaxForm(String[] strs, int m, int n) {
    int l = strs.length;
    int[][][] dp = new int[l+1][m+1][n+1];
    
    for (int i = 0; i < l+1; i++) {
        int[] nums = new int[]{0,0};
        if (i > 0) {
            nums = calculate(strs[i-1]);
        }
        for (int j = 0; j < m+1; j++) {
            for (int k = 0; k < n+1; k++) {
                if (i == 0) {
                    dp[i][j][k] = 0;
                } else if (j>=nums[0] && k>=nums[1]) {
                    dp[i][j][k] = Math.max(dp[i-1][j][k], dp[i-1][j-nums[0]][k-nums[1]]+1);
                } else {
                    dp[i][j][k] = dp[i-1][j][k];
                }
            }
        }
    }
    
    return dp[l][m][n];
}

private int[] calculate(String str) {
    int[] res = new int[2];
    Arrays.fill(res, 0);
    
    for (char ch : str.toCharArray()) {
        if (ch == '0') {
            res[0]++;
        } else if (ch == '1') {
            res[1]++;
        }
    }
    
    return res;
}

猜你喜欢

转载自blog.csdn.net/xiezongsheng1990/article/details/80044785