贪心算法,动态规划,01背包问题总结

01背包问题

背包问题是用来介绍动态规划算法最经典的例子。
https://blog.csdn.net/qq_38410730/article/details/81667885

题目描述:
假设山洞里共有a,b,c,d ,e这5件宝物(不是5种宝物),它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包, 怎么装背包,可以才能带走最多的财富。

首先要理解他的状态转移方程
V[i,j] =V[i-1,j] j<W(i)
V[i,j] =max{V[i-1,j] , V[i-1,j-W(i)] +Pi } j>=W(i)

V[i,j]表示当前背包容量 j,前 i 个物品最佳组合对应的价值。
Pi表示第i个物品的价值,Wi表示第i个物品的体积。
这个状态转移方程就是要做决策:为了价值最大化,第i个物品要放到背包中么?

从理解的角度来说,这个方程的意思是:
当放入第i个物品时:
1、首先判断第i物品放不放的下,通过判断j是否大于第i物品的重量W(i)
如果放不下j<W(i),那么价值不变;
2、如果放得下j>=W(i),那么就在放入这个物品的价值加上剩余背包容量的价值 和 不放入该物品的 价值中选最大值。

从作用的角度来说,这个方程是用来填表的。将已经查找过得子问题答案记录下来。
填V[i,j]二维表,i是有多少个物品,j是有多大容量,填完表结果也就出来了,物品数一般不会太多,但是j的容量太大,二维表建立的就很大,这是一个问题。

贪心算法

题目1

一个数组有 N 个元素,求连续子数组的最大和。 例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3.

#include <iostream>
#include<climits>
using namespace std;
int main(){
    int n,curSum=0,maxSum=INT_MIN;
    cin>>n;
    int arr[n];
    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
        curSum+=arr[i];
        if(curSum>maxSum)
            maxSum=curSum;
        
        if(curSum<0)
            curSum=0;
    }
    cout<<maxSum<<endl;
    return 0;
}

动态规划

#include<iostream>
using namespace std;
void findpath(int v[][9],int p[],int w[],int num,int capa,int path[])
{
       int i=num;
       int j=capa;
       int temp;
       while(i>0)
       {
              if(v[i][j]==v[i-1][j])
                     path[i--]=0;
              else
              {     
                     path[i]=1;
                     j=j-w[i];
                     i--;
              }
       }
}
int main()
{
       int number=4, capacity=8;
       int w[5]={0,2,3,4,5}; //重量
       int p[5]={0,3,4,5,6};  //价值
       int v[5][9]={0};  //动态规划表

       int path[5]={0};  //用来保存是否装入背包 
       for(int i=1;i<=number;i++)
              for(int j=1;j<=capacity;j++)
              {
                     if(j<w[i])
                            v[i][j]=v[i-1][j];
                     else
                            v[i][j]=max(v[i-1][j],v[i-1][j-w[i]]+p[i]);
              }
       cout<<v[number][capacity]<<endl;
       findpath(v,p,w,number,capacity,path);

       cout<<path[1]<<path[2]<<path[3]<<path[4]<<endl;
}

表格填完,最优解就是v[number][capacity];

//二维数组
#include<iostream>
using namespace std;
long dp[1001][1001];
int main()
{
       	int n,sum,p[1000]={0};
       	cin>>n>>sum;   
	for(int i=1;i<=n;i++)
              cin>>p[i];
       	for(int i=0;i<=n;i++)
              dp[i][0]=1;
       	for(int j=1;j<sum;j++)
              dp[0][j]=0;
       	for(int i=1;i<=n;i++)
              for(int j=0;j<=sum;j++)    
              {
                     if(j<p[i])
                            dp[i][j]=dp[i-1][j];
                     else
                            dp[i][j]=dp[i-1][j]+dp[i-1][j-p[i]];
              }
       cout<<dp[n][sum]<<endl; 
       return 0;
 }
//一维数组的方法
#include<iostream>
using namespace std;
long dp[1001];
int main()
{

       	int n,sum,p[1000]={0};
       	cin>>n>>sum;  
	for(int i=1;i<=n;i++)
              cin>>p[i];
   	dp[0]=1;
       	for(int j=1;j<sum;j++)
              dp[j]=0;
       	for(int i=1;i<=n;i++)
              for(int j=sum;j>=p[i];j--) 
              {
                            dp[j]=dp[j]+dp[j-p[i]];
              }
       cout<<dp[sum]<<endl;    
       return 0;

 }

在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值