01背包基本算法

01背包、有依赖的背包

前置知识: 讲解067、讲解06&-二维动态规划及其空间压缩技巧 【必备】课程的动态规划大专题从讲解066开始,建议从头开始学习会比较系统

本节课讲述: 01背包:每个物品 要和不要 两种可能性展开 有依赖的背包:多个物品变成一个复合物品(互斥),每件复合物品 要和怎么要 多种可能性展开 不能用01背包来解,但是非常重要的问题:非负数组前k个最小的子序列和问题(来自b站左神视频整理得出的笔记)明天更新分组背包

典型的背包模板

P1048 [NOIP2005 普及组] 采药

连接:[P1048 NOIP2005 普及组] 采药 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

提交441.67k

通过200.26k

时间限制1.00s

内存限制125.00MB

保存

难度普及−

历史分数100

提交记录  查看题解

进入讨论版

相关讨论

查看讨论

推荐题目

题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

第一行有 22 个整数 TT(1≤T≤10001≤T≤1000)和 MM(1≤M≤1001≤M≤100),用一个空格隔开,TT 代表总共能够用来采药的时间,MM 代表山洞里的草药的数目。

接下来的 MM 行每行包括两个在 11 到 100100 之间(包括 11 和 100100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出在规定的时间内可以采到的草药的最大总价值。

输入输出样例

输入 #1复制

70 3
71 100
69 1
1 2

输出 #1复制

3

说明/提示

【数据范围】

  • 对于 30%30% 的数据,M≤10M≤10;

  • 对于全部的数据,M≤100M≤100。

public static void main(String[] args) throws IOException {
    BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    String[] s = bf.readLine().split(" ");
    //总时间
    int time = Integer.parseInt(s[0]);
    //种类
    int n = Integer.parseInt(s[1]);
    int [] cost = new int[n+1];
    int [] value = new int[n+1];
    for (int i = 1;i<n+1;i++){
        s = bf.readLine().split(" ");
        cost[i] = Integer.parseInt(s[0]);
        value[i] = Integer.parseInt(s[1]);
    }
    int ans = 0;
    int [][]dp = new int[n+1][time+1];
    //当前从第一种草药开始,要或者不要
    //先填好第一种草药
    for (int i = 1;i<=n;i++){
        //来到第i种草药
        for (int j = 0;j<=time;j++){
            //如果不要当前草药
            dp[i][j] = dp[i-1][j];
            //如果要当前草药
            if (j -cost[i]>=0){
                dp[i][j] = Math.max(dp[i-1][j-cost[i]]+value[i],dp[i][j]);
            }
        }
    }
   PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
   out.print(dp[n][time]);
   out.close();
}

494. 目标和

已解答

中等

给你一个非负整数数组 nums 和一个整数 target

向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
static int count ;
    public static int findTargetSumWays(int[] nums, int target) {
        int n = nums.length;
        count = 0;
        int sum = 0;
        for(int i:nums){
            sum+=i;
        }
        // p = 正数和
        // t = 负数和
        //sum - p = t
        //target = p-t = p-(sum - p);
        //p = (sum+target)/2
        if((sum+target)%2==1||sum<target){
            return 0;
        }
        int  p = (sum+target)/2;
​
        return process(nums,p);
    }
    
    //转换为了01背包问题
    public static int process(int []nums,int p){
        int n = nums.length;
//        int [][] dp = new int[n+1][p+1];
//        dp[0][0] = 1;
//        for (int row = 1;row<=n;row++){
//            for (int col = 0;col<=p;col++){
//                dp[row][col] = dp[row-1][col];
//                if ((col-nums[row-1])>=0){
//                    dp[row][col]+=dp[row-1][col-nums[row-1]];
//                }
//            }
//        }
​
        int [] dp = new int[p+1];
        dp[0] = 1;
        for (int i = 1;i<=n;i++){
            for (int j = p;j>=0;j--){
                if (j>=nums[i-1]){
                    dp[j]+=dp[j-nums[i-1]];
                }
            }
        }
        return dp[p];
    }

1049. 最后一块石头的重量 II

已解答

中等

提示

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 xy,且 x <= y。那么粉碎的可能结果如下:

  • 如果 x == y,那么两块石头都会被完全粉碎;

  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x

最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0

示例 1:

输入:stones = [2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
public int lastStoneWeightII(int[] stones) {
    int sum = 0;
    for(int i:stones){
        sum+=i;
    }
    int near = near(stones,sum);
    return sum - near - near;
}
​
//二维动态规划数组压缩了
public static int near(int [] stones,int near){
    int []dp = new int [near+1];
    for(int i = 1;i<=stones.length;i++){
        for (int j = near;j>=0;j--){
            if(j - stones[i-1]>=0){
                dp[j]=Math.max(dp[j],dp[j-stones[i-1]]+stones[i-1]);
            }
        }
    }
    return dp[near];
}
  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值