算法分析—动态规划(01背包问题)

算法分析—动态规划(背包问题)

最近在学习动态规划,对于背包问题十分感兴趣。写下自己的感受,也算也是对自己学习的监督。

01背包问题

问题描述:

给定N种物品和一个背包。物品i的重量是Wi,其价值位Vi ,背包的容量为C。问应该如何选择装入背包的物品,使得转入背包的物品的总价值为最大??

限制条件:

1<=N<=10

1<=vi,wi<=100

1<=W<=10000

根据动态规划解题步骤:1)划分子问题:设置dp[i+1][j]:=从前i个物品中挑选不超过j的物品总价值最大值

                                             2)列出状态转移方程:dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]) 这里的理解就很关键了,从前i个物品中挑选不超过j的物品总价值最大值等价于两种情况1.不挑选第i个物品,从前i-1个物品中挑选不超过j的物品总价值最大值 2.挑选第i个物品,从前i-1个物品中挑选不超过j-w[i]的物品总价值最大值.

                                             3代码如下算法分析—动态规划(01背包问题)_第1张图片

                                    注意一点:在二维数组赋值时,要考虑j是否大于w[i],不然就出错。

01背包问题优化空间复杂度

在解决最基础的问题后,我们就考虑下一个问题,降低01背包问题空间复杂度。直白一点就是用一维数组来代替二维数组。

先贴出代码:

算法分析—动态规划(01背包问题)_第2张图片

                            1)划分子问题:设dp1[ j ] 为前i个物品放到容量为 j  的背包最大价值。等价之前的 dp[ i ][ j ]。不过由于dp1[ j ]受 i 的值影响,所以第i次的结果可能会覆盖之前i-1的  结果。                

                             2)列出状态转移方程:我们在来回顾前面算法的状态转移方程

                               也就是说我们要把max中两个状态转移方程改写成一元数组问题。那么问题就简单了。

                             1.dp[ i ][ j ]即不挑选第i 个物品,把前 i -1个物品放入 容量为 j的背包最大价值。由于dp1[ j ] 在i 从0到n 的循环过程中,dp1[ j ]也在不断改变。但是反应到状态转移方程,dp[ i ][ j ]  改写为dp1[j] ,但是要注意此时dp1[ j ]保存是 i-1的时候的值。

                            2.dp[i][j-w[i]]+v[i] 即挑选第i 个物品,把前 i -1个物品放入 容量为 j-w[ i ]的背包最大价值。所以dp[i][j-w[i]]+v[i]改写成一元数组是dp1[j-w[i]]+v[i]。

                           3)倒叙输出原因

回过头来,我有一个疑问,为什么第二个循环要从W->w[ i ]而不是 从 w[ i ]到W呢?

原因是这样的,如果采取for(int  j =w [ i ] ; j< =W;j++)

那么第一个状态方程不受影响    dp[ i ][ j ]保存还是前 i -1个物品放入 容量为 j的背包最大价值,不受影响,但是第二个状态方程受到影响,因为他保存是前 i 个物品放入 容量为 j的背包最大价值,即dp1[j-w[i]]存储是dp[i  ][ j-w[ i ]  ],而正确应该是dp[i -1 ][ j-w[ i ]  ].如果不能理解可以画个图来帮助思考。

总的代码如下:

#include 
#include 
#include 


using namespace std;

int n;
int w[100];
int v[100];
int W;
int max_n=0;
int max_m=0;
int dp[100][100];//定义动态规划数组
int dp1[100];
void solve();
void solve1();

void solve()
{
    for(int i=0;i=w[i];j--)
        {

            {
                dp1[j]=max(dp1[j],dp1[j-w[i]]+v[i]);
            }
        }
    }
    printf("%d",dp1[W]);
}

int main()
{
    cin>>W;//挑选物品的总重量
    cin>>n;//物品的数量
    for(int i=0;i>w[i];//每个物品的重量
        max_n++;
    }
    for(int i=0;i>v[i];//每个物品的价值
        max_m++;
    }
    memset(dp,0,sizeof(dp));//初始化整个数组
    solve();
    solve1();
    return 0;
}

哈哈哈哈,就是这么简单,我真聪明











你可能感兴趣的:(算法分析—动态规划(01背包问题))