回归内卷:五一动规题解

生活依旧在继续

让我们在蓝桥杯的国赛中

都能得到自己满意的答案!

目录

一、开心的金明

解析:

代码:

二、榨取kkksc03

解析:

代码:

三、合唱队形

解析:

代码:

四、导弹拦截

解析:

代码:

五、纪念品分组

解析:

代码:


一、开心的金明

解析:

一个基础的01背包问题,每一次购买a价格的物品可以获得b的价值,a为价格,b为价格*重要度

因此,输入的时候:

arr[i][0]=sc.nextInt();

arr[i][1]=arr[i][0]*sc.nextInt();

因为这题数据m<25,所以直接进行循环即可,常规01背包写法

代码:

import java.util.Scanner;

public class 开心的金明 {
    static Scanner sc = new Scanner(System.in);
    static int n = sc.nextInt();//总金额
    static int m = sc.nextInt();//商品类型
    static int[][] arr = new int[m][2];
    public static void main(String[] args) {
        for (int i = 0; i < m; i++) {
            arr[i][0] = sc.nextInt();//存放价格
            arr[i][1] = sc.nextInt() * arr[i][0];//存放价值
        }
        int []dp=new int[n+1];
        for(int i=0;i<m;i++)
        {
            for(int j=n;j>=arr[i][0];j--)//注意从m开始
            {
                    dp[j]=Math.max(dp[j],dp[j-arr[i][0]]+arr[i][1]);//dp
            }
        }
        System.out.println(dp[n]);
    }
}

二、榨取kkksc03

解析:

 这题和上面的开心的金明差不多,不过条件多了一个,那么我们只需要将上面for循环从m开始那边,再增加一个for循环即可

代码:

import java.util.Scanner;

public class 榨取kkksc03 {
    static Scanner sc=new Scanner(System.in);
    static int n=sc.nextInt();
    static int m=sc.nextInt();
    static int t=sc.nextInt();
    static int [][]arr=new int[1010][1010];
    static int [][]brr=new int[1010][2];

    public static void main(String[] args) {
        for (int i=1;i<=n;i++){
            brr[i][0]=sc.nextInt();
            brr[i][1]=sc.nextInt();
            for (int j=m;j>=brr[i][0];j--)//金币
                for (int k=t;k>=brr[i][1];k--){//时间
                    arr[j][k]=Math.max(arr[j][k],arr[j-brr[i][0]][k-brr[i][1]]+1);
                }
        }
        System.out.println(arr[m][t]);
    }
}

三、合唱队形

解析:

 

首先,我们定任意一个点为最大的点,即T(i-1)<Ti>T(i+1)

那么,因为i不确定,我们就进行一次遍历,依次对每一个值为最大值设置

由此,我们可以得到从1-----n每一个值的最长上升序列

同理,我们再从后往前,计算一个从后往前的最长上升序列

因为每一个位置都存在一个从前往后和从后往前

所以当两个值相加最大时,为最多存下的人数

因此,其余人数为最小出列人数

代码:

import java.util.Scanner;

public class 合唱队形 {
    static Scanner sc=new Scanner(System.in);
    static int n=sc.nextInt();
    static int []arr=new int[n+2];
    static int []brr=new int[n+2];
    static int []crr=new int[n+2];
    public static void main(String[] args) {
        for (int i=1;i<=n;i++){
            arr[i]=sc.nextInt();
        }
        for (int i=1;i<=n;i++){//正向的最长上升序列
            for (int j=i;j>=0;j--){
                if (arr[j]<arr[i])
                    brr[i]=Math.max(brr[i],brr[j]+1);
            }
        }
        for (int i=n;i>=1;i--){//逆序的最长上升序列(即最长下降序列)
            for (int j=i;j<=n+1;j++){
                if (arr[i]>arr[j]){
                    crr[i]=Math.max(crr[i],crr[j]+1);
                }
            }
        }
        int max=0;
        for (int i=0;i<=n;i++){
            max=Math.max(max,brr[i]+crr[i]-1);//减一为当前位置值在往前往后都有计算,计算次数为2
        }
        System.out.println(n-max);

    }
}

四、导弹拦截

解析:

这题只知道

第一问求:最长不上升序列

第二问求:最长上升序列

但是,nlogn的方案没有思路,不会写,但是用上面的方案写可以过n方的部分

具体代码和上面合唱队列差不多

代码:

import java.util.Scanner;

public class 导弹拦截 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        String[] ss = s.split(" ");
        int n = ss.length;
        int[] arr = new int[n];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = Integer.parseInt(ss[i]);
        }
        int max = -1;
        int min = -1;
        int[] brr = new int[n];
        int[] crr = new int[n];
        for (int i = 0; i < n; i++) {
            brr[i] = 1;
            crr[i] = 1;
            for (int j = 0; j < i; j++) {
                if (arr[j] >= arr[i]) {
                    brr[i] = Math.max(brr[i],brr[j] + 1);
                } else {
                    crr[i] = Math.max(crr[i], crr[j] + 1);
                }
            }
            max = Math.max(max, brr[i]);
            min = Math.max(min, crr[i]);

        }
        System.out.println(max);
        System.out.println(min);
    }
}

五、纪念品分组

解析:

这题用的是贪心的思想(运用双指针)

先将整个数组排序,升序降序都可以(我是直接升序排序了)

假设5个值50  60  75  80  90

然后给定的条件是 每组不超过130

那么第一次判断50+90,超过

那么下一次判断50和80,不超过

下一次判断为60和75,超过

下一次60和60,不超过

再下一次判断的是75和50,因为75>50,所以不再判断,结束,输出为4

代码:

import java.util.Arrays;
import java.util.Scanner;

public class 纪念品分组 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int m=sc.nextInt();//每组最大价格
        int n=sc.nextInt();//种类
        int []arr=new int[n+1];
        for (int i=1;i<=n;i++){
            arr[i]=sc.nextInt();
        }
        Arrays.sort(arr,1,n+1);
        for (int i=1;i<=n;i++){
            System.out.print(arr[i]+" ");
        }
        int l=1,r=n,sum=0;
        while (r>=l) {
            if (arr[r] + arr[l] <= m) {
                l += 1;
            }
            sum += 1;
            r--;
        }
        System.out.println(sum);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值