贪心入门
贪心概念
若在求解一个问题时,能根据每次所得到的局部最优解,推导出全局最优或最优目标。那么,我们可以根据这个策略,每次得到局部最优解答,逐步而推导出问题,这种策略称为贪心法。
贪心的重点:你是否知道这是一道贪心的题目,此外怎么样才是最好的贪心策略,剩下的基本交给按策略排序就可以了。接下来我们一起看几道简单的贪心类型的题目吧!
简单贪心问题
1. 排队打水问题(姚班1296)
有n个人在一个水龙头前排队接水,假如每个人的接水的时间为T_i,请编程找出一种n个人排队的顺序,使得n个人的平均等待时间最小。
假设下一个人接着打水的这个切换过程不消耗时间,且注意,每个人的等待时间包括自己接水的时间和排队等待接水的时间。(仔细审题,反正我一开始写错了)
输入输出格式
输入
第一行一个整数 nn,1≤n≤10001≤n≤1000。
第二行分别为每个人的接水时间 T_1,T_2,...,T_nT1,T2,...,Tn,用空格隔开,T_i≤10^6Ti≤106。
输出
第一行为最优的排队顺序,即编号 1 \sim n1∼n 的一种排列,每两个数字之间用空格隔开。
第二行为这种排列方案下的平均等待时间(保留两位小数)。
输入输出样例
样例
输入1
10
56 12 1 99 1000 234 33 55 99 812
输出1
3 2 7 8 1 4 9 6 10 5
532.00
【算法分析】
由于排队时,越靠前面的计算的次数越多,显然越小的排在越前面得出的结果越小(可以用数学方法简单证明,这里就不再赘述),所以这道题可以用贪心法解答,基本步骤:
(1)将输入的时间按从小到大排序;
(2)将排序后的时间按顺序依次放入每个水龙头的队列中;
(3)统计,输出答案。
重点:如何构造结构体,需要时间跟编号!
完整代码如下:
#include <bits/stdc++.h>
using namespace std;
struct water
{
int bh;
int time;
}; //构造结构体
bool cmp(water a,water b)
{
return a.time<b.time; //按时间从小到大排序
}
water a[10005];
int main()
{
int n;
double d,sum=0,mus=0,avg;
cin>>n;
for(int i=1; i<=n; i++)
{
a[i].bh=i; //循环变量i就是编号
cin>>a[i].time;
}
sort(a+1,a+n+1,cmp); //按时间排序
int m=n;
for(int i=1;i<=n;i++)
{
sum=sum+a[i].time*m; //统计总时间,易错点
m=m-1;
}
avg=sum/n;
for(int i=1; i<=n; i++)
{
cout<<a[i].bh<<" ";
}
cout<<endl<<fixed<<setprecision(2)<<avg;
return 0;
}
Copy
2. 最小等待时间(合肥市2019年第五题)姚班1648
超市的收银处有 n 位顾客在排队等着付款,他们的编号依次为 1,2,…,n。由于每个顾客所购的商品不同,因此付款时所需的等待时间也就不一样。给出这 n 个人每个人单独付款所需的时间。而顾客不同的付款顺序,所有顾客总等待时间是不一样的,收银员想知道所有顾客总等待时间最少是多少。