背包问题

01背包

1.记忆化搜索+dfs

//记忆化搜索+dfs
int rec(int i, int j) {
    if (dp[i][j] >= 0)//已经计算过的就可以使用之前的值
        return dp[i][j];
    int res;
    if (i == n)res = 0;//0-n-1,第n个当然不能放了
    else if (j < w[i])res = rec(i + 1, j)//不能放的时候第i个最大价值等于i+1的
    else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);
    return dp[i][j] = res;//记忆化
}

2.dp[i][j]为从第i个物品开始挑选总重小于j时,总价值的大小

物品从0-n-1编号

dp[n][j]=0;

dp[i][j]= dp[i+1][j](j< w[i])

dp[i][j]= max(dp[i+1][j],dp[i+1][j-w[i]]+v[i])(其他)

要求i必须先求出i+1,所以i是逆序

for(int i=n-1;i>=0;i--)
for (int j = 0; j <= w; j++) {
    if (j < w[i])
        dp[i][j] = dp[i + 1][j];
    else
        dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
}
cout << dp[0][w] << endl;

3.dp[i+1][j]:从前i个物品中选出总重量不超过j的物品时总价值的最大值

dp[1][j]=dp[0][j]=0;

dp[i+1][j]=dp[i][j];

dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i])

for (int i = 0; i < n; i++) {
    for (int j = 0; j <= w; j++) {
        if (j < w[i])
            dp[i + 1][j] = dp[i][j];
        else
            dp[i + 1][j] = max(dp[i][j], dp[i][j - w[i]] + v[i]);
    }
}
cout << dp[n][w];

4.滚动数组优化空间(常用)

for (int i = 0; i < n; i++) {
    for (int j = w; j >= w[i]; j--) {//逆序
        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
    }
}
cout << dp[n] << endl;

完全背包

原理:

dp[i+1][j]的计算中选k个的情况,与在dp[i+1][j-w[i]]中的k-1个情况完全相同,所以dp[i+1][j]可由dp[i+1][j-w[i]]的计算得到

max{dp[i][j-k*w[i]]+kv[i]|0<=k}
=max(dp[i][j],max{dp[i][j-k*w[i]]+k
v[i]|k>=1})
=max(dp[i][j],max{dp[i][j-w[i]-k*w[i]]+k*v[i]|k>=0}+v[i])
=max(dp[i][j],dp[i+1][j-w[i]]+v[i])

for (int i = 0; i < n; i++) {
    for (int j = 0; j <= w; j++) {
        if (j < w[i]) {
            dp[i + 1][j] = dp[i][j];
        }
        else
            dp[i + 1][j] = max(dp[i][j], dp[i + 1][j - w[i]] + v[i]);
    }
}
cout << dp[n][w];

滚动数组优化

for (int i = 0; i < n; i++) {
    for (int j = w[i]; j <= w; j++) {
            dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
    }
}
cout<<dp[w];
上一篇:如何在Arcgis中对图斑进行自上而下,从左往右地编号


下一篇:矩形重叠