洛谷贪心题单思路讲解

橙题:纪念品分组

链接: 纪念品分组在这里插入图片描述

思路:

1.我们需要最少的组数,那么最大价值的商品我们需要判断是否有可以与它组成一队的商品,因此第一步需要完成排序
2.如果有一件价值商品为X,可以与价值为Y的商品组队,那么价值≤X的商品都可以与价值为Y的商品组队,但是为了价值最大化,我们选择X与Y组合
3.我们考虑完了配对方案,那么考虑实现形式,我们需要判断当前最大值是否有可以与它配对的最小值,因此我们需要进行一个左右端点值的判断,所以这题可以使用双指针
4.判断完了使用双指针,那么开始判断指针移动的方式,因为每一次都是以最大值进行判定,所以从右往左,每一组都会-1,而左端点则需要满足可以与右端点组合时,左往右+1.结束点为左端点>=右端点

纪念品分组代码

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;//组数+1
            r--;//右端点左移
        }
        System.out.println(sum);
    }
}

黄题:删数问题

链接: 删数问题

在这里插入图片描述

思路:

1.我们拥有n个数,要去除k个数,即保留n-k个数,让保留的数尽可能小,那么我们要使在最前方的数尽可能小
2.考虑了需要让前面的数尽可能小,那么就要考虑怎么让它尽可能小,我们保留第一位数的时候,后面还需要保留n-k-1个数,所以第一个数是在原来的n个数中的第1至n-k-1中的最小的一个数,假设下标为x的数是最小数,那么第二个数则从第x+1个数至n-k-2个数的最小值,因此这题也是使用双指针
3.因为输出不含前置0,所以需要特判出现0之前是否有数字出现,如果没有则不进行输出,如果有,则正常输出

删数问题代码

import java.util.Scanner;

public class 删数问题 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String ss=sc.next();//字符串表示输入的高精度整数
        int k=sc.nextInt();//删除k个数
        k=ss.length()-k;//保留的个数
        int l=-1,y=0;//l记录左指针,y记录是否出现有效数字
        for (int i=0;i<k;i++){
            int min=10;//最大的整数为9
            for (int j=l+1;j<=ss.length()-k+i;j++){
                if (ss.charAt(j)-'0'<min){
                    l=j;//更改左指针
                    min=ss.charAt(j)-'0';//更改最小值
                }
            }
            if (min!=0) y=1;//判定是否出现有效数字
            if (y!=0||i+1>=k)  System.out.print(min);
        }
    }
}

黄题:跳跳

链接: 跳跳

在这里插入图片描述

跳跳代码

思路:

1.因为跳跃距离无限制,所以我们要使每一次跳跃花费的力气最大,则让每一次的差值最大即可

在这里插入图片描述

2.判断了每一次选择差值最大,则需要进行排序和双指针计算,因为值特别大,因此记得long(C的话是long long)
3.判断完了双指针计算的方式,如果是普通双指针的话就太简单了,所以考虑稍微复杂一点的,(arr[l]-arr[i])²+(arr[l-1]-arr[i])²是不是就是从最大值跳下来,再跳回新的最大值,从右指针回到右指针,就不需要特判在左指针的情况怎么跳了
import java.util.Arrays;
import java.util.Scanner;

public class 跳跳 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int []arr=new int[n];
        for (int i=0;i<n;i++) arr[i]=sc.nextInt();
        Arrays.sort(arr);//排序
        long count= (long) arr[n - 1] *arr[n-1];//第一次先跳到最大值
        int l=n-1;
        for (int i=0;i<l;i++){
            count= (long) (Math.pow((arr[l]-arr[i]),2)+Math.pow((arr[l-1]-arr[i]),2)+count);//跳下去再回跳
            l--;//右指针前移
        }
        System.out.println(count);
    }
}

绿题:分组

链接: 分组

在这里插入图片描述

思路:

1.因为要求每一组的数都是连续的,那么肯定是需要排序的,所以第一步先进行排序
2.因为需要连续的,但是排序后每个数可能出现重复,我们计算一下每一个数出现的次数进行存放
3.因为是连续的,所以当判断到不连续的时候,就会断开,并且有些数只出现一次,有些出现多次,所以需要运用双指针来进行下一次分组的起始数值
4.如果一个数比后面的连续数出现次数多了,那么到这个数就应该截止,因为我们需要的是最短连续个数最大,所以到这个数与后面的数进行连接一定比所有连续数个数-1后产生的数大

在这里插入图片描述

分组代码

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

public class 分组 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int []arr=new int[n+1];
        arr[n]=1010101010;
        for (int i=0;i<n;i++)arr[i]=sc.nextInt();
        Arrays.sort(arr);
        int [][]brr=new int[n+10][2];
        int x=0;
        for (int i=0;i<n;i++){
            brr[x][0]=arr[i];
            brr[x][1]++;
            if (arr[i]!=arr[i+1])x++;
        }
        int l=0;
        int min=100010;
        int count=0;
        for (int i=0;i<x;i++){
            brr[i][1]--;//数值出现次数-1
            if (brr[i][1]==0) l=i+1;//说明该数出现次数已经没了
            if (brr[i][0]+1==brr[i+1][0]){//判断是否与后面连续
                if (brr[i][1]!=brr[i+1][1]) {//前面的数剩余次数不大于连续的后面数字次数
                    count++;
                }else{
                    count++;
                    i=l-1;
                    min=Math.min(min,count);
                    count=0;
                }
            }else{
                count++;
                i=l-1;
                min=Math.min(min,count);
                count=0;
            }
        }
        System.out.println(min);
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
贪心算法(Greedy Algorithm)是一种常见的算法思想,它在每一步都选择最优的选择,从而希望得到全局最优解。在实际应用中,贪心算法常常用于求解最小生成树、最短路径、背包问题等。 下面以求解背包问题为例,介绍MATLAB中的贪心算法实现。 假设有一个背包,它的容量为c,同时有n个物品,每个物品有自己的重量w和价值v。现在需要从这些物品中选择一些放入背包,使得背包中物品的总价值最大。 可以采用以下贪心策略:每次选择价值最高的物品放入背包,直到背包容量不足以放下当前最优物品时停止选择。 以下是MATLAB实现代码: ```matlab function [maxValue,selected] = greedyKnapsack(c,w,v) % 贪心算法求解背包问题 % c:背包容量,w:物品重量,v:物品价值 % maxValue:背包最大价值,selected:选择的物品编号 n = length(w); % 物品个数 ratio = v./w; % 计算物品的性价比 % 按性价比从大到小排序 [~,index] = sort(ratio,'descend'); maxValue = 0; % 背包最大价值 selected = zeros(1,n); % 选择的物品编号 for i = 1:n if w(index(i)) <= c % 当前物品可以放入背包 selected(index(i)) = 1; c = c - w(index(i)); maxValue = maxValue + v(index(i)); else % 当前物品不能完整放入背包 selected(index(i)) = c/w(index(i)); maxValue = maxValue + v(index(i))*selected(index(i)); break; end end end ``` 代码中,首先计算每个物品的性价比,然后按照性价比从大到小排序。接着,依次选择性价比最高的物品放入背包,直到背包容量不足以放下当前最优物品时停止选择。最后返回背包最大价值和选择的物品编号。 贪心算法虽然简单,但并不一定能得到全局最优解。在实际应用中,需要根据具体问题来选择合适的算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值