周六900C++班级-2022-11-26-完全背包

完全背包定义

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

从定义中可以看出,与01背包的区别01背包最多只能拿一件物品,完全背包则不然,只要空间够多,一种物品我可以拿n件!

01背包的状态转移方程为:dp(i,j)=max(dp(i-1,j),dp(i-1,j-w[i])+v[i])
完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-w)+v[i])

我们可以看出,完全背包的动态转移方程max中第二项为i,而不是i-1。

为什么呢?

 

 

我从代码的角度阐释一下这个问题!
注意我们现在并没有对dp数组进行降维!
我们的j是从0开始的,依次递增这个是完全背包的关键,也是与01背包本质的区别
dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
首先要满足完全背包的动态转移方程,就要先知道dp(i,j-w)的大小
正好我们是从0开始的,并不是从后往前,也就是当求到dp(i,j)时
dp(i,j-w),在前面已经求过!!!
所以我们可以应当理顺的求出dp(i,j)而不再是向01背包要考虑前i-1时候的状态!

 

完全背包的优化

然后我们根据01背包的优化原则对,完全背包进行优化!
优化后的动态方程
dp[j]=max(dp[j],dp[j-w]+v)

复制代码
#include<bits/stdc++.h>
using namespace std;
int dp[30005]; //dp[j] = 最大容量为j时的最大价值
int n,m;
int w[105],v[105];//w重量,v价值 
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++)cin>>w[i]>>v[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=w[i];j<=m;j++)
        {    //dp[j] = dp[j] , dp[j-w[i]]+v[i]
            dp[j] = max(dp[j],dp[j-w[i]]+v[i]);  
        }
    }
    cout<<dp[m];
    return 0;
}
复制代码

 

完全背包问题

复制代码
#include<bits/stdc++.h>
using namespace std;

int n,m;
int w[105],v[105],dp[30005];

int main(){
    cin>>m>>n;
    for(int i=1;i<=n;i++)cin>>w[i]>>v[i];
    for(int i=1;i<=n;i++){
        for(int j=w[i];j<=m;j++){
            
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    printf("max=%d",dp[m]);
    return 0;
}
View Code
复制代码

货币系统

复制代码
#include<bits/stdc++.h>
using namespace std;
long long int dp[3005]; //dp[j] = 当面值为j时的最大方案数 
int n,m; //n个物品,m容量
int w[20]; //w[i]每个货币的面值 
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>w[i];
    dp[0] = 1;
    for(int i=1;i<=n;i++)
    {
        for(int j=w[i];j<=m;j++)
        {
            dp[j] = dp[j] + dp[j-w[i]];
        }
    }
    cout<<dp[m];
     return 0;
}
View Code
复制代码

买书

复制代码
#include<bits/stdc++.h>
using namespace std;
int dp[3005];
int m;
int w[20] = {0,10,20,50,100};
int main()
{
    cin>>m;
    dp[0] = 1; //当j-w[i]=0时证明刚好可以购买第i种面值的书 
    for(int i=1;i<=4;i++)
    {
        for(int j=w[i];j<=m;j++)
        {
            dp[j] = dp[j] + dp[j-w[i]];
        }
    }
    cout<<dp[m];
     return 0;
}
View Code
复制代码

最小乘车费用

复制代码
#include<bits/stdc++.h>
using namespace std;
int dp[30005];
int n,m;
int w[300],v[300];
int main()
{//最小乘车费用5734 
    memset(dp,9999,sizeof(dp));
    dp[0] = 0;
    n = 10;
    for(int i=1;i<=n;i++)cin>>v[i];
    cin>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=m;j++)
        {
            dp[j] = min(dp[j],dp[j-i]+v[i]);
        }
    }
    cout<<dp[m];
     return 0;
}
View Code
复制代码

 

 

 

 

posted @   CRt0729  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示