动态规划之01背包

来源:互联网 发布:python sin函数 编辑:程序博客网 时间:2024/05/18 15:56

有n件物品,每种只有一个,第i种物品的体积是Vi, 重量为Wi,选择一些物品装到一个容量为C的背包中,使得背包体积在不超过C的前提下重量尽量大

这是最基础的动态规划的问题,这类问题最重要的就是要找到状态转移方程。这里我们可以引用“阶段”的概念,也就是我们的每一次决策都是放在前一次决策的基础上,比如决定第i个物品是否要放入背包,就要在前i次决策的基础上进行比较。
我们再来看一下这个背包的状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);这时的i是对前i-1个物品做完决策以后的第I次决策,j是此时的背包的重量,dp[i][j]的最优解是(不放第i件物品与上一个状态中已用j质量的价值,放了第i件物品与上一个状态中放了后质量为[j-weight[i]]+第i件物品的价值)进行比较

#include<bits/stdc++.h>using namespace std;const int maxn=1005;int weight[maxn],value[maxn],dp[maxn][maxn];int main(){        int N,V;        cin>>N>>V;//N是一共的物品数量,V是背包所能承受的最大质量        for(int i=1;i<=N;i++)            cin>>weight[i];//每件物品的质量        for(int i=1;i<=N;i++)            cin>>value[i];//每件物品的价值        //dp[i][j]表示将前i件物品处理完后,背包已经用了大小为j的质量,所对应的的最大价值        for(int i=1;i<=N;i++) {//将第i件物品放在前面(i-1)件物品的状态上                //j为已用体积!!!!!            for(int j=0;j<=V;j++) {//j从第i件物品的质量开始,因为j为已用体积,也就是从已用体积为j的状态中挑出最优解                    if(j<weight[i])dp[i][j]=(i==1?0:dp[i-1][j]);                    else dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);            }        }        cout<<dp[N][V]<<endl;    return 0;}

这里还有一个更厉害的操作,在前面我们用的数组是二维的,也就是我们要对每一个阶段的大于Vi的所有状态进行更新,这样看来时间是不能更快了,但在空间上我们还可以更优化, 既然每一个东西只用一次,我们可不可以在输入的时候就对每个阶段进行决策?也就是把二维数组变成1维,而每次决策放在输入后,答案当然是可以的

#include<bits/stdc++.h>using namespace std;int main(){    int N,V;    cin>>N>>V;    vector<int>dp(10000,0);    while(N--) {        int weight, value;        cin>>weight>>value;        for(int j=V;j>=weight;j--)            dp[j]=max(dp[j],dp[j-weight]+value);    }    cout<<dp[V]<<endl;    return 0;}

这里我们为了保证每种物品只用了一次,我们的状态遍历必须从后往前,因为从前往后的话,我们的每次决策都会用到前面的数据,而我们前面的数据有可能是已经更新过的,所以我们必须从后往前更新

原创粉丝点击