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

一个问题可以用动态规划法求解的先决条件:

1、最有子结构性质:当问题的最优解包含了其子问题的最优解时,成该问题具有最有子结构性质。

2、重叠子问题:每次产生的子问题并不总是新问题,有些子问题被反复计算多次。

满足了以上两个条件的问题可以考虑用动态规划法求解,它是一种自底向上的递归算法

0-1背包问题是最广为人知的动态规划问题之一,大体上0-1背包问题分为两种:物品无限的背包问题和物品有限的背包问题(即0-1背包问题)。

问题描述:有N件物品和一个容量为C的背包。第i件物品的容积是volume[i],重量是weight[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

多说无益,放码过来。(Talk is easy,show me the code!)

/**0-1背包问题,f[i][j]用来表示前i个物品装到容量为j的背包中的最大重量**/
#include 
#include 
#define MAX  1000
using namespace std;

int weight[MAX];
int volume[MAX];
int f[MAX][MAX];
//问题在于你怎么看待这个状态f[i][j]
//是看成把每一个物品按照0,1,2,3...编号后,从第一个物品开始进行选择,是要还是不要
//还是看成放入背包中的i个物品的最大重量,这个i并没有顺序的意思,而只是背包中物品数量的统计


int getMax(int m,int n)
{
    return m>=n ? m : n;
}

int Knapsack(int n ,int c)
{
    for(int i=0;ij)
            f[i][j] = f[i-1][j];
            else{
            f[i][j] = getMax(f[i-1][j],f[i-1][j-volume[i]]+weight[i]);
            }
        }
    }
    return f[n][c];
}

int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int n; //背包中物品的个数
    int c; //背包容量
    while(scanf("%d %d",&n,&c) != EOF)
    {
        cout << "请依次输入背包中每件物品的体积和重量" << endl;
        for(int i = 1;i<=n;++i)
        {
            scanf("%d %d",&volume[i],&weight[i]);
        }
        int result = Knapsack(n,c);
        cout << result << endl;
    }
    fclose(stdin);
    fclose(stdout);
}

理解与看法其实,刚一开始我是不理解这种算法的。想要真正理解两层循环,我觉得最重要的是真正理解f[i][j]的意义。我刚开始,是这样想的:f[i][j]是背包中能放下i个物品的最大重量,这样带入到状态转移方程


是正确的,而f[i][j]真正的含义是对要所有物品进行从1开始编号,依次对物品进行选择是否放入到背包中,这样编号为i的物品在被选择前背包中的最大重量。其实,从状态转移方程我们也可以看到我们算法设计的核心思路:编号为i的物品是还是不放到背包中。然而,我们根据状态转移方程的第一个式子,又容易产生这样的疑问:既然编号为i的物品能被放入到背包中,那显然放进来比选择不放进来要质量大啊。这样想乍一看没错,其实,你忽略了一点,把编号为i的物品放入背包,可能会使得编号为1到i-1的物品无法放入,你刚才的想法是默认了在放入编号为i的物品后,编号为1到i-1的的物品都可以被放入。


最近状态一直不好,希望能够在5月下半旬有转机,还是希望自己能够自律,坚持,快乐和思考!

你可能感兴趣的:(数据结构和算法,ACM,CC++)