背包问题

动态规划入门——背包问题

注意计算机的最大优点在于它的强大计算功能,以及存储功能,你能做的就是合理利用这些优点该循环就循环,该遍历就遍历。要知道简洁的算法毕竟不是那么多。

最基础、最重要、最好玩——01背包*

 问题描述:
     有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
    例如:V=10     物品重量分别为 w[1]=3,w[2]=4,w[3]=6,w[4]=10,w[5]=8;      物品价格分别为V[1]=3,V[2]=3,V[3]=7,V[4]=9,V[5]=10;   
    ## First    
    常规思维,太复杂。学要考虑的情况极其复杂,你可以试一下!!!!!
     ##Second
      打表理解——————保证在计算背包时每一次将背包装到最优。

在这里插入图片描述

代码实现

状态转移方程           直接上一维    dp[j]=max(dp[j],dp[j-w[i]]+v[i]); ( j>=w[i] )   dp[j]——表示当背包容量为j时最优的价值  相当于是一次一次更新状态---->俗称状态转移方程。
#include<stdio.h>
#define max(a,b) a>b?a:b
int main()
{
       int i,j,n=5,V=50;
       int dp[100]={0},w[100],v[100];
       for(i=0;i<n;i++)
       scanf("%d%d",&w[i],&v[i]);
       for(i=0;i<n;i++)
       for(j=V;j>=w[i];j--)
       dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
       //   dp[V]中就是最大值;
       return0;
}

完全背包(背包问题的另一类问题)

问题描述:
一个背包,N种物品,每种物品的价值,所需空间;
求最优的解。。。。。。
一、打表理解。
二、状态转移方程:与01背包问题类似只是在第二重循环时括号内容会发生变化。
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
## 代码

#include<stdio.h>
#define max(a,b) a>b?a:b
int main()
{
	int n,i,j,V;
	int dp[100],w[100],v[100];
	scanf("%d%d",&n,&V);
	for(i=0;i<n;i++)
	scanf("%d%d",&w[i],&v[i]);
	for(i=0;i<n;i++)
	for(j=w[i];j<=V;j++)        //保证背包一次一次被遍历到;
	dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	//dp[V]即最优解;
         return 0;
}

这是一篇高度浓缩的博客

完全背包一般包含两类问题:
1. 求背包恰好装满;
2. 可以不装满,只希望价格最大;
3. *********约束条件(分界线————是否玩转)
## 第一类问题
求背包能装的最小的价值且恰好能装满;
方法:
1,初始化dp[0]=0;
2, 初始化dp[1,2,3,…]为极小值;
结果判定

若dp[m]=INT (极小值) 则装不满 ?????不好理解 自己打表一目了然;
## 第二类问题
dp[0…m]=0;
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

多重背包(背包问题的另一形式)

问题描述:
有一个背包V内存,N种物品,每种物品w,v,N; 所需空间,价值,数量;
求最优解;
解释一下:
其实这就是升级版本的01背包问题,第i个物品有N个,不就可以算出一共有几个物品吗?
加一重循环就行


for(int i=0;i<n;i++)
     for(int k=0;k<N[i];k++) 
          for(j=V;j>=w[i];j--)
          dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

------------->但是这是一种费事的方法,价值不大;
## 核心(二进制优化)
将一个数不停地分解分解再分解

#include<stdio.h>
#define max(a,b) a>b?a:b
void yoouhuaa(int w[], int v[], int N[], int n, int &t)
{
         int i,j;
         for(i=0;i<n;i++){
           for(j=1;j<=N[i];j*=2)
             {
                   W[t]=w[i]*j;
                   V[t++]=v[i]*j;
                   N[i]-=j;
             }
             W[t]=w[i]*N[i];
             V[t++]=v[i]*N[i];
       }
}
int main()
{
	int i,j,n,Q  ,t=0;
	int w[100],v[100],N[100],dp[10000],W[1000],V[1000]
	scanf("%d%d",&n,&V);
	for(i=0;i<n;i++)
	scanf("%d%d%d",&w[i],&v[i],&N[i]);
	yoouhua(w,v,N,n,t);
	for(i=0;i<t;i++)
	   for(j=Q;j>=W[i];j--)
	   dp[j]=max(dp[j],dp[j-W[i]]+V[i]);
	   //      dp[t] 即是最优的解;
}

OK;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值