初识DP-01背包问题及其空间优化

版权声明:个人学习笔记记录 https://blog.csdn.net/Ratina/article/details/84636724

01背包是经典的DP问题,个人是看这位的blog看懂的:点这里~~~~~~
感觉这个讲的十分详细,很好理解。


借一个例题来示范吧(洛谷 P1049 装箱问题)

题目描述:

有一个箱子容量为 V(正整数,0 ≤ V ≤ 20000),同时有n个物品(0< n ≤30),每个物品有一个体积(正整数)。

要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

输入格式:

1个整数,表示箱子容量
1个整数,表示有n个物品
接下来n行,分别表示这n个物品的各自体积

输出格式:

1个整数,表示箱子剩余空间。


为使箱子剩余空间最小,那就是装入的物品总体积要最大,典型的背包问题,DP思想就不多说了。

先看无优化的代码(二维数组):

#include<iostream> 
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
    int n, V, v[35];
    int dp[35][20005];
    int i, j;
    memset(dp, 0, sizeof(dp));   //初始化为0
    cin >> V >> n;
    for (i = 1; i <= n; i++)
        cin >> v[i];
    for (i = 1; i <= n; i++)
        for (j = 1; j <= V; j++)
        {
            if (v[i] <= j)    //如果 i 还装得下,就比较装入 i 和不装入 i 的收益。
                dp[i][j] = max(v[i] + dp[i - 1][j - v[i]], dp[i - 1][j]);
            else              
                dp[i][j] = dp[i - 1][j];  //如果 i 装不下,就继承上一个的收益。
        }
    cout << V - dp[n][V] << endl;
    return 0;
}

· 优化

这里可以进行空间优化,将二维数组换为一维数组,时间也能相对优化一些。
重点在于一维数组 dp[200005] 的自更新,观察一下这部分代码:

for (j = 1; j <= V; j++)
{
	if (v[i] <= j)
		dp[i][j] = max(v[i] + dp[i - 1][j - v[i]], dp[i - 1][j]);
	else
		dp[i][j] = dp[i - 1][j];
}

①可以看到当 v[i] > j 时,执行dp[i][j] = dp[i - 1][j],所以在一维数组中,这些部分就不需要变动了 。

②再者,当 j <= v[i] 时,执行 dp[i][j] = max(v[i] + dp[i - 1][j - v[i]], dp[i - 1][j])
可以看到,以 j = 3为例,dp[i][3]只可能和dp[i-1][3]、dp[i-1][2]、dp[i-1][1]、dp[i-1][0] 有关,所以一维数组只要从后向前更新,就不会有影响。

那么优化后的这段代码为:

for (j = V; j >= v[i]; j--)    //从V开始,更新到 v[i] 停止
{
	dp[j] = max(v[i] + dp[j - v[i]], dp[j]);
}

以下优化后完整代码:

#include<iostream> 
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
    int n, V, v[35];
    int dp[20005];
    int i, j;
    memset(dp, 0, sizeof(dp));   //依旧要初始化
    cin >> V >> n;
    for (i = 1; i <= n; i++)
        cin >> v[i];
    for (i = 1; i <= n; i++)
    {
        for (j = V; j >= v[i]; j--)
        {
            dp[j] = max(v[i] + dp[j - v[i]], dp[j]);
        }
    }
    cout << V - dp[V]<< endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/84636724