简单贪心:
简单贪心算法简介:
贪心算法是求解一类最优化问题的算法,考虑在当前状态下局部最优(或较优)的策略,来使全局的结果达到最优(或较优)。要想获得最优结果,则要求中间的每步策略都是最优的。
简单贪心应用举栗🌰:
月饼
题目描述
月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价以及市场的最大需求量,试计算可以获得的最大收益是多少。
注意: 销售时允许取出一部分库存。样例给出的情形是这样的:假如有三种月饼,其库存量分别为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;
}
输出如下
算法总结:
贪心算法是用来解决一类最优化的问题,由局部最优来推得全局最优。贪心算法适用的问题一定满足最优子结构性质,即一个问题的最优解可以由它的子问题的最优解构造出来。