贪心算法小结

本文介绍了贪心算法的概念及其在求解最优子结构问题中的应用。通过两个实例——防晒霜分配和畜栏预定问题,展示了如何利用贪心策略进行降序排序以找到局部最优解。在防晒霜分配问题中,按SPF值降序排列,确保每头奶牛使用到最合适的防晒霜;在畜栏预定问题中,通过小根堆维护畜栏结束时间,有效安排牛的吃草顺序。这两个问题都通过贪心算法实现了高效的解决方案。
摘要由CSDN通过智能技术生成

首先要明确一个概念:最优子结构的性质是什么?
       即当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质.

贪心算法的定义                    百度词条的定义
    贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

解题的一般步骤是:
1.建立数学模型来描述问题;
2.把求解的问题分成若干个子问题;
3.对每一子问题求解,得到子问题的局部最优解;
4.把子问题的局部最优解合成原来问题的一个解。

AcWing_110.防晒
     问题可以抽象成给定一些区间和一些有重复的点,若点包含于区间则匹配成功,求最大匹配数,即二分图的匹配问题。首先,可以按左端点降序排序,然后将各点也降序排序。因为对于每一头奶牛而言,当然是要选择目前来说满足条件的最差的防晒霜,而最差的定义,就是选择满足奶牛条件的SPF最大的那一瓶防晒霜.
为什么降序排序?因为要保证对于每一头奶牛而言,它用的是当前可以使用的最差的防晒霜,因为值越小的防晒霜,有可能让更多的牛使用。

Java代码(贪心+自定义排序规则)

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

class SpfCover implements Comparable<SpfCover>{
    int spf,cover;
	public SpfCover(int spf, int cover) {
		this.spf = spf;
		this.cover = cover;
	}
	@Override
	public int compareTo(SpfCover o) {
		if(spf == o.spf)
			return o.cover - this.cover;	
		return o.spf - this.spf;
	}
}

class SPFRange implements Comparable<SPFRange>{
	int minSPF,maxSPF;
	public SPFRange(int minSPF, int maxSPF) {
		this.minSPF = minSPF;
		this.maxSPF = maxSPF;
	}
	
	@Override
	public int compareTo(SPFRange o) {
		if(minSPF == o.minSPF)
			return o.maxSPF - this.maxSPF;	
		return o.minSPF - this.minSPF;
	}
}

public class 防晒 {
	private static Scanner sc;
	public static void main(String[] args) {
		sc = new Scanner(System.in);
		int c = sc.nextInt();
		int l = sc.nextInt();
        SpfCover []sp = new SpfCover[l+1];
        SPFRange []arr = new SPFRange[c+1];
		for(int i=0;i<c;i++) {
			int min = sc.nextInt();
			int max = sc.nextInt();
			arr[i] = new SPFRange(min, max);
		}
		
		for(int i=0;i<l;i++) {
			int spf = sc.nextInt();
			int cnt = sc.nextInt();
			sp[i] = new SpfCover(spf,cnt);
		}
		
		Arrays.sort(arr,0,c);
		Arrays.sort(sp,0,l);
		int ans=0;
		for(int i=0;i<c;i++) {
			for(int j=0;j<l;j++) {
				if(sp[j].spf<=arr[i].maxSPF && sp[j].spf>=arr[i].minSPF && sp[j].cover!=0) {
					sp[j].cover--;
					ans++;
					break;
				}
			}
		}
		System.out.println(ans);
	}
}

注:此题的贪心策略是对区间左端点和spf点集进行降序排列

AcWing_111.畜栏预定
y老师题解
     算法步骤:
1。将所有牛按开始吃草的时间排序;
2。用小根堆维护当前所有畜栏的最后一头牛的吃草结束时间;
3。如果当前的牛可以安排在堆顶的畜栏中,则将其安排进去,否则就新建一个畜栏;

Java代码(贪心+自定义排序规则)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
//猜测运行要3秒多,带优化
class Pair implements Comparable<Pair> {
	int first, second,index;

	public Pair(int first, int second,int index) {
		this.first = first;
		this.second = second;
		this.index = index;
	}

	@Override
	public int compareTo(Pair o) {
		return first - o.first;
	}
}

class Stall implements Comparable<Stall> {
	int r;
	ArrayList<Integer> cowId = new ArrayList<>();
	int idx;

	public Stall(int r, int cowId, int idx) {
		this.r = r;
		this.cowId.add(cowId);
		this.idx = idx;
	}

	@Override
	public int compareTo(Stall o) {
		return r - o.r;
	}

}

public class Main{
	private static Scanner sc;

	public static void main(String[] args) {
		sc = new Scanner(System.in);
		int n = sc.nextInt();

		Pair[] cows = new Pair[n + 1];
		for (int i = 0; i < n; i++) {
			int l = sc.nextInt();
			int r = sc.nextInt();
			cows[i] = new Pair(l, r, i+1);
		}

		Arrays.sort(cows, 0, n);

		PriorityQueue<Stall> queue = new PriorityQueue<>();
		while (!queue.isEmpty())
			queue.poll();
		for (int i = 0; i < n; i++) {
			if (queue.isEmpty() || queue.peek().r >= cows[i].first) {
				Stall stall = new Stall(cows[i].second, cows[i].index, queue.size() + 1);
				queue.offer(stall);
			} else {
				Stall stall = queue.poll();
				stall.r = cows[i].second;
				stall.cowId.add(cows[i].index);
				queue.offer(stall);
			}
		}

		System.out.println(queue.size());
		int[] res = new int[n + 1];
		while (!queue.isEmpty()) {
			Stall stall = queue.poll();
			for (int cowid : stall.cowId) {
				res[cowid] = stall.idx;
			}
		}
		for (int i = 1; i <= n; i++) {
			System.out.println(res[i]);
		}
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星航夜空的帆舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值