附加条件的0-1背包问题

Posted Huterox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了附加条件的0-1背包问题相关的知识,希望对你有一定的参考价值。

文章目录

前言

水一篇博文证明我还活着~

问题描述(0-1背包问题)

ok,咱们先来说说这个背包问题是怎么样的呢。
首先背包问题就是,在一个有限的背包内,尽可能去装下更多的物品,每个物品都是有自己的质量和价值的,我们要让价值最大化!

那么在这里我们先来说说,为什么背包问题可以是一个动态规划的题目,对于动态规划有一个明显的特征,当前状态取决于上一个状态,例如斐波那契数列(当然关于斐波那契数列我们又可以使用矩阵幂乘法来加速解决问题)。那么在背包问题里面,显然,下一个物品要不要放置,取决于当前的背包容量和上一个物品有没有放置,之后放置之后的值就是 max(没有放置上一个物品,放置了上一个物品)而,上一个物品又是取决于上上个物品和上物品,这样我们发现这个就相当于变成了走楼梯,斐波那契数列的问题。这样一来我们就懂了,背包问题其实就是在原来简单的动态规划的前提下,加入了最大化(最小化)的约束,也就是多加了一个约束!

那么在理解了背包问题之后,我们来说说在蓝桥杯题目里面我见到的类似背包问题的题目,首先最明显的就是那个走格子问题,在格子上面有一定的value,然后让这个value最大。

例如:

那这个呢,怎么说呢,就是在有限的空间内,或者是一个限制之内,放置最多的物品去达到最大的价值。

打表

想要搞清楚这个问题呢,咱们还是得打表。

此外咱们还有两个数组分别表示重量和价值。

这里的话我不太想了复述了,前面的话是有写过的。
我今天这里只说一下那个附加条件的怎么做。

题目

思路

首先很明显是个背包问题,但是这里有些个条件要处理一下。

原来我们考虑背包的话只是需要考虑那个背包的容量,那么这里的就是不仅要考虑这个,还要考虑那个不能相交的条件。

然后在这里引出了一个问题,就是我们在dp的时候是在做选择,那么我如何知道我选择了哪些商品的问题。所以需要你对这个0-1背包问题比较熟练。然后知道如何处理之后,咱们就能够动手了。

代码

package com.huterox.testweek02;

import java.util.ArrayList;
import java.util.Scanner;

public class week209 
    //目前的想法就是暴力搜索

//6
//1 1 2
//1 4 2
//1 7 2
//4 1 2
//4 4 2
//4 7 2


    static ArrayList<ArrayList<Integer>> trees = new ArrayList<>();

    public static void main(String[] args) 
        //初始化,我们把这个当作有约束的0-1背包问题
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] w = new int[n];
        int totalArea  = 0;
        for (int i=0;i<n;i++)
            ArrayList<Integer> temp = new ArrayList<>();
            int row  = scanner.nextInt();
            int col = scanner.nextInt();
            int r = scanner.nextInt();
            totalArea+=r*r;//边界限制
            temp.add(row);
            temp.add(col);
            temp.add(r);
            w[i] = r*r;
            trees.add(temp);
        

        int[] dp = new int[totalArea+1];
        int[] place = new int[n];
        dp[0]=0;
        for (int i=0;i<trees.size();i++)
            for (int j=totalArea;j>=w[i];j--) 
                if (i == 0) 
                    //此时是种第一颗树
                    dp[j] = Math.max(dp[j], dp[j - w[i]] + w[i]);
                    place[i] = i;
                
                else  
                    //把其他的树种下去
                    if(j - w[i]>=0)
                    
                        int lay_now  =  dp[j - w[i]] + w[i];
                        if(lay_now>=dp[j])
                            //这里需要轮询判断
                            boolean flag = true;
                            for (int k=0;k<=i-1;k++)
                               if(!is_vaild(trees.get(i),trees.get(place[k])))
                                   flag = false;
                               
                            

                            if(flag)
                                place[i] = i;
                                dp[j] = lay_now;
                            else
                                place[i] = place[i-1];
                        
                        else 
                            dp[j] = dp[j];
                            place[i] = place[i-1];
                        
                    

                
            
        

        System.out.println(dp[totalArea]);
        System.out.println("种了这几颗树");
        for (int s : place) 
            System.out.printf("%d--",s);
        

    

    public static boolean is_vaild(ArrayList<Integer> last,ArrayList<Integer> now)
        //判断当前的树和即将种下的树有没有冲突,条件判断出问题了
        double cha_x = (double)last.get(0) - now.get(0);
        double cha_y = (double)last.get(1)-now.get(1);
        double distance = (double)last.get(2)+last.get(2);
        return (Math.pow(cha_x, 2) + Math.pow(cha_y, 2) >= Math.pow(distance, 2));
    


可以看到种了1 3 5这三棵树

ok, 水玩了~

以上是关于附加条件的0-1背包问题的主要内容,如果未能解决你的问题,请参考以下文章

0-1背包

模板0-1背包

背包问题,贪心算法实现

背包问题模板

0-1背包回溯

0-1背包问题的回溯法代码