初步理解:贪心算法

怎么理解贪心算法 

      贪心算法的本质就是找到每个阶段的局部最优,从而去推导全局最优。这么说可能有点抽象,举一个简单的例子:假设有一堆不同面额的钞票,从中取出十张,如何取才能得到最多的钱呢?这时候我们会有一个想法,只要每次取其中面额最大的钞票,依次取十次,那么所得的钞票总数就是最多的。在这个例子中,每次取出面额最大的钞票就是每个阶段里的局部最优,而所取到的钞票总数就是全局最优。从中我们可以看出,局部最优可以推出全局最优,这就是一个贪心策略。

注意

贪心算法所得到的结果不一定是最优结果(有时候会是最优解),但是都是相对接近最优解的结果。

 因为贪心算法没有固定的解题方法,基本都是先找出每个阶段的局部最优方法,用局部最优方法来推导全局最优的解法,所以为了更好的理解贪心算法,我们来看几个例子以及其解决方法

一,今年暑假不AC

Problem Description

“今年暑假不AC?”

“是的“

”“那你干什么呢?”

“看世界杯呀,笨蛋!”

“@#$%^&*%...”

确实如此。世界杯来了,球迷的节日也来了,预计非常多ACMer也会抛开电脑。奔向电视了。

作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其他的节目。比方新闻联播(永远不要忘记关心国家大事)、很6+7、超级女生,以及王小丫的《开心辞典》等等。如果你已经知道了全部你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)

Input

输入数据包括多个測试实例。每一个測试实例的第一行仅仅有一个整数n(n\u003C=100)。表示你喜欢看的节目的总数。然后是n行数据,每行包括两个数据Ti_s,Ti_e (1\u003C=i\u003C=n),分别表示第i个节目的開始和结束时间,为了简化问题,每一个时间都用一个正整数表示。\nn=0表示输入结束,不做处理。

Output

对于每一个測试实例,输出能完整看到的电视节目的个数,每一个測试实例的输出占一行。Sample Input

12 1 3 3 4 0 7 3 8 15 19 15 20 10 15 8 18 6 12 5 10 4 14 2 9 0

Sample Output

5

 思路分析

我们要想知道最多可以观看多少节目,就要清楚每个节目的开始时间和结束时间,以及从中可以推出每个节目持续的时间长短。为了方便比较,我们先将各个时间段依照结束时间进行排序(按结束越早遍历。节目愈多再从第一个节目开始,假设下一节目开始时间大于上一节目的开始时间则进行该节目。依次递推。为了使代码的结构清晰方便理解。可以使用数组进行存储数据。

代码示例

import java.util.*;
public class jinnianshujiabuAC {
	public static void sort(int start[], int end[]) {//对开始时间和结束时间进行排序
	for (int i = 0; i < end.length - 1; i++) {
	for (int j = 0; j < end.length - 1 - i; j++) {
	if (end[j] > end[j + 1]) {
	int t1 = end[j];
	end[j] = end[j + 1];
	end[j + 1] = t1;

	int t2 = start[j];
	start[j] = start[j + 1];
	start[j + 1] = t2;
	}
	}
	}

	}

	public static void main(String[] args) {
	Scanner input = new Scanner(System.in);

	while (input.hasNext()) {
	int n = input.nextInt();
	if (n == 0) {
	break;
	}
	int[] start = new int[n];
	int[] end = new int[n];
	for (int i = 0; i < n; i++) {
	start[i] = input.nextInt();
	end[i] = input.nextInt();
	}
	sort(start, end);
	int count=1;
	int t=end[0];
	for (int i = 1; i < start.length; i++) {
	if(t<=start[i]){


	t=end[i];
	count++;
	}
	}
	System.out.println(count);
	}

	}

	}

二,胖老鼠的交易

Problem Description

胖老鼠准备M磅的猫粮,准备与守卫仓库的猫交易他最爱吃的JavaBean。仓库有N个房间。第i个房间包含J[I]的JavaBeans,需要F[I]磅的猫粮交换。每个房间可以按比例部分交换,你的任务是计算胖老鼠能获得的最多的JavaBeans。

Input

输入数据有多组,每组数据第一行包括两个正整数M、N,接下来有N行,每行有两个数J[I]和F[I],表示第i个房间JavaBean数量和需要的猫粮数量。当M和N都为-1输入结束。所有数字不会超过1000。

Output

对于每组输入数据,计算胖老鼠能获得的最大JavaBean数量并输出,结果保留三位小数,每个输出占一行。

样例输入

5 3

7 2

4 3

5 2

20 3

25 18

24 15

15 10

-1 -1

样例输出

13.333

31.500

思路分析

要想使胖老鼠得到的JAVABeans最多,那么就要使胖老鼠在每个房间收获的JAVABeans是最多的。我们可以先对房间按照单位猫粮所能收益的最大JAVABeans的值进行排序,从前往后进行遍历,如果猫粮有剩余就兑换。为了使代码写起来更加方便和更加准确,我们可以创建对象进行调用

 代码示例

import java.util.Arrays;
import java.util.Scanner;
public class zhuixingzu {
			public static void main(String[] args) {
						Scanner input = new Scanner(System.in);
						while(input.hasNext()) {
						int n = input.nextInt();
						if(n == 0){
						break;
						}
						F[] perform = new F[n];
						for (int i = 0; i < n; i++) {
						perform[i] = new F();
						perform[i].setStar(input.nextInt());
						perform[i].setEnd(input.nextInt());
						}
						Arrays.sort(perform);
						int count = 1;
						int curEndTime = perform[0].getEnd();
						for (int i = 0; i < n; i++) {
						if (perform[i].getStar() >= curEndTime) {
						count++;
						curEndTime = perform[i].getEnd();
						}
						}
						System.out.println(count);
						}
						}
						}
						class F implements Comparable<F>{
						private int star;
						private int end;
						F(){}
						public F(int star, int end) {
						this.star = star;
						this.end = end;
						}

						public int getStar() {
						return star;
						}

						public int getEnd() {
						return end;
						}

						public void setStar(int star) {
						this.star = star;
						}

						public void setEnd(int end) {
						this.end = end;
						}

						@Override
						public int compareTo(F o) {
						return Integer.compare(this.end,o.end);
						}
						}

三,追星族

题目描述

小明最近迷上很多的女明星,恰逢她们正在巡回演出,得知所有的演出安排后,小明计划去看演出。但是有一些演出的时间重合,他在这个时间只能选择看其中一场演出,小明想尽可能多的看一些完整的演出,请你想想办法小明怎么安排能看更多完整的演出。

输入格式

输入数据有多组,每组数据的第一行有一个整数n(n≤100),表示演出的总数,然后是n行数据,每行包括两个数据si,ti (1≤i≤n),分别表示第i场演出的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。

输出格式

对于每组输入数据,输出小明最多能看完整演出的场数,每个输出占一行。

样例输入

11

3 5

1 4

5 7

0 6

5 9

3 8

6 10

8 11

2 13

8 12

12 14

0

样例输出

4

 思路分析

我们要想知道最多可以观看多少演出,就要清楚每场演出的开始时间和结束时间。这是一个区间调度问题,可以使用贪心算法来解决。首先将所有的演出按照开始时间进行排序,然后遍历排序后的演出列表,对于每一场演出,如果它的开始时间大于等于上一场演出的结束时间,那么就可以看这场演出,将计数器count加1。最后输出计数器的值。我们可以调用comparable接口来实现演出之间的比较

代码示例

import java.util.Arrays;
import java.util.Scanner;
public class zhuixingzu {
			public static void main(String[] args) {
						Scanner input = new Scanner(System.in);
						while(input.hasNext()) {
						int n = input.nextInt();
						if(n == 0){
						break;
						}
						F[] perform = new F[n];
						for (int i = 0; i < n; i++) {
						perform[i] = new F();
						perform[i].setStar(input.nextInt());
						perform[i].setEnd(input.nextInt());
						}
						Arrays.sort(perform);
						int count = 1;
						int curEndTime = perform[0].getEnd();
						for (int i = 0; i < n; i++) {
						if (perform[i].getStar() >= curEndTime) {
						count++;
						curEndTime = perform[i].getEnd();
						}
						}
						System.out.println(count);
						}
						}
						}
						class F implements Comparable<F>{
						private int star;
						private int end;
						F(){}
						public F(int star, int end) {
						this.star = star;
						this.end = end;
						}

						public int getStar() {
						return star;
						}

						public int getEnd() {
						return end;
						}

						public void setStar(int star) {
						this.star = star;
						}

						public void setEnd(int end) {
						this.end = end;
						}

						@Override
						public int compareTo(F o) {
						return Integer.compare(this.end,o.end);
						}
						}

以上是我们作业中的几道贪心算法的练习题,我将其整理下来并做了简单总结,希望能帮助大家更好的理解贪心算法,也希望大家多多在评论区交流学习,一起学习编程知识。

新手小白报道,请大家多多指教!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CT.狭路

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

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

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

打赏作者

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

抵扣说明:

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

余额充值