算法笔记之贪心(简单贪心&区间贪心)

简单贪心:

简单贪心算法简介:

贪心算法是求解一类最优化问题的算法,考虑在当前状态下局部最优(或较优)的策略,来使全局的结果达到最优(或较优)。要想获得最优结果,则要求中间的每步策略都是最优的。

简单贪心应用举栗🌰:

月饼

题目描述

月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价以及市场的最大需求量,试计算可以获得的最大收益是多少。

注意: 销售时允许取出一部分库存。样例给出的情形是这样的:假如有三种月饼,其库存量分别为18、15、 10万吨,总售价分别为75、72、 45亿元。如果市场的最大需求量只有20万吨,那么最大收益策略应该是卖出全部15万吨第二种月饼以及5万吨第三种月饼,获得72 +45/2 = 94.5 (亿元)。

输入格式

每个输入包含1个测试用例。每个测试用例先给出一个不超过1000的正整数N表示月饼的种类数以及不超过500 (以万吨为单位)的正整数D表示市场最大需求量;随后一行给出N个正数表示每种月饼的库存量(以万吨为单位);最后一-行给出N个正数表示每种月饼的总售价(以亿元为单位)。数字间以空格分隔。

输出格式

对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后两位。

输入样例

3 20
18 15 10
75 72 45

输出样例

94.50

题目大意

已知月饼需求量和n种月饼各自的库存量和总售价,求如何销售可以获得最大收益。

解题思路

贪心
采用“总是选择单价最高的月饼出售,可以获得最大的利润”的策略。根据库存量和总售价计算出该种月饼的单价。按单价从高到低排序,从单价高的月饼开始枚举。
供不应求:将该种月饼全部卖出。②供大于求: 只提供需求量大小的月饼。

代码如下

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

struct cake{
	double kucun;  //库存
	double sum;  //总售价
	double price;  //单价
}c[10010];
bool cmp(cake a,cake b){
	return a.price>b.price;  
}
int main(){
	int n;
	double d;
	scanf("%d%lf",&n,&d);
	for(int i=0;i<n;i++){
		scanf("%lf",&c[i].kucun);
	}
	for(int i=0;i<n;i++){
		scanf("%lf",&c[i].sum);
		c[i].price = c[i].sum/c[i].kucun;  //月饼单价
	}
	sort(c,c+n,cmp);  //单价从高到低排序
	double ans=0;
	for(int i=0;i<n;i++){
		if(c[i].kucun<=d){  //供不应求
			d -= c[i].kucun; 
			ans += c[i].sum;
		}else{  //供大于求
			ans += c[i].price*d;
			break;
		}
	}
	printf("%.2lf\n",ans);
	return 0;
}
组个最小数

题目描述

给定数字0~9各若干个。可以任意顺序排列这些数字,但必须全部使用。目标是使得最后得到的数尽可能小(注意:0不能做首位)。例如,给定两个0、两个1、三个5和一个8,得到的最小的数就是10015558。
现给定数字,请编写程序输出能够组成的最小的数。

输入格式

每个输入包含1个测试用例。每个测试用例在一行中给出十个非负整数,顺序表示所拥有数字0、数字1……数字9的个数。整数间用一个空格分隔。十个数字的总个数不超过50,且至少拥有一个非0的数字。

输出格式

在一行中输出能够组成的最小的数。

输入样例

2 2 0 0 0 3 0 0 1 0

输出样例

10015558

解题思路

先从1~9 中选择个数不为0的最小的数字输出,然后从 0~9 输出相应个数的数字,每个数字输出次数为剩余个数。由于第一位不能是0,因此第一个数字必须从 1~ 9中选择最小的存在的数字。

代码如下

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

int main(){
	int cnt[10];  //数字0~9的个数
	for(int i=0;i<10;i++){
		cin>>cnt[i];
	}
	for(int i=1;i<10;i++){  //从1~9中选择个数不为0的最小数字
		if(cnt){
			cout<<i;
			cnt[i]--;
			break;
		}
	}
	for(int i=0;i<10;i++){  //从0~9输出相应个数的数字
		for(int j=0;j<cnt[i];j++){
			cout<<i;
		}
	}
	return 0;
}

区间贪心:

区间贪心算法简介:

区间不相交问题:

给出n个开区间(x,y),从中选择尽可能多的开区间,使得这些开区间两两没有交集。举个栗子🌰:对开区间(1,3)、(2, 4)、 (3, 5)、 (6, 7)来说,可以最多选出三个区间(1, 3)、 (3,5)、(6, 7),互相没有交集。

①开区间C2包含开区间C1,则应当选择C1,因为这样可以有更大的空间容纳其他开区间。

②把所有开区间按左端点x从大到小排序,去除区间包含的情况,一定 有y1> y2>…> yn成立。则应当选择C1,因为先选择左端点最大的区间,右边的一段是一定不会和其他区间重叠的。
在这里插入图片描述

区间选点问题:

给出n个闭区间[x,y],求最少需要确定多少个点, 才能使每个闭区间中都至少存在一个点。举个栗子🌰:对闭区间[1, 4]、[2, 6]、[5, 7]来说,需要两个点(例如3、5)才能保证每个闭区间内都有至少有一个点。

区间选点问题和区间不相交问题的策略是一致的。
①闭区间C2包含闭区间C1,则应当选择C1,因为在C1中取点可以保证这个点一定在C2内。
②把所有闭区间按左端点x从大到小排序,因为每个闭区间中都需要存在一个点,因此对左端点最大的区间C1来说,只要取左端点这样这个点就能覆盖到尽可能多的区间。

区间贪心应用举栗🌰:

区间不相交

题目描述

给出n个开区间(x,y),从中选择尽可能多的开区间,使得这些开区间两两没有交集。

输入样例

4
1 3
2 4
3 5
6 7

输出样例

3

代码如下

#include<iostream>
#include <algorithm>
#include <cstdio>
using namespace std;

struct C{
	int x,y;  //开区间左右端点
}c[105];
bool cmp(C a,C b) {
	if(a.x != b.x) 
		return a.x > b.x;  //按左端点从大到小排序
	else
		return a.y<b.y;  //左端点相同的按右端点从小到大排序
}
int main(){
	int n; 
	while(cin>>n,n){
		for(int i=0;i<n;i++){
			cin>>c[i].x>>c[i].y;
		}
		sort(c, c+n, cmp) ;//区间排序
		int ans = 1, lastx = c[0].x;  //ans不相交区间个数  lastx上一个被选区间的左端点
		for(int i=1;i<n;i++){ 
			if(c[i].y <= lastx){  //如果该区间右端点在lastx左边 
				lastx = c[i].x;  //以c[i]为新选择的区间
				ans++;
			}
		}
		cout<<ans;

	}
	return 0;
}

输出如下
在这里插入图片描述

区间选点

题目描述

给出n个闭区间[x,y],求最少需要确定多少个点, 才能使每个闭区间中都至少存在一个点。

输入样例

3
1 4
2 6
5 7

输出样例

2

代码如下

#include<iostream>
#include <algorithm>
#include <cstdio>
using namespace std;

struct C{
	int x,y;  //开区间左右端点
}c[105];
bool cmp(C a,C b) {
	if(a.x != b.x) 
		return a.x > b.x;  //按左端点从大到小排序
	else
		return a.y<b.y;  //左端点相同的按右端点从小到大排序
}
int main(){
	int n; 
	while(cin>>n,n){
		for(int i=0;i<n;i++){
			cin>>c[i].x>>c[i].y;
		}
		sort(c, c+n, cmp) ;//区间排序
		int ans = 1, lastx = c[0].x;  //ans不相交区间个数  lastx上一个被选区间的左端点
		for(int i=1;i<n;i++){ 
			if(c[i].y < lastx){  //如果该区间右端点在lastx左边 
				lastx = c[i].x;  //以c[i]为新选择的区间
				ans++;
			}
		}
		cout<<ans;

	}
	return 0;
}

输出如下
在这里插入图片描述

算法总结:

贪心算法是用来解决一类最优化的问题,由局部最优来推得全局最优。贪心算法适用的问题一定满足最优子结构性质,即一个问题的最优解可以由它的子问题的最优解构造出来。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值