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

前言

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

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

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

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

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

例如:

image.png

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

打表

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

在这里插入图片描述

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

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

题目

在这里插入图片描述

思路

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

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

然后在这里引出了一个问题,就是我们在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, 水玩了~

猜你喜欢

转载自blog.csdn.net/FUTEROX/article/details/123619416