一、组队刷题(先来道简单的)
某天,吴大佬准备和菜鸡Tirpitz一起组队刷题,聪明的吴大佬把题目分成了n个板块,每个板块有w[i]个题目,刷完这个板块需要消耗吴大佬m[i]的精力。吴大佬没有必要在一个板块死磕,/毕竟有咸鱼队友Tirpitz/。相反,如果他消耗m[i]%的精力时,他会解决这个专题w[i]%的题目,现在吴大佬想给聪明的你一个任务,让你计算吴大佬一共能做多少道题目?(没有a完就算成小数累加哦w/这个也算是吴大佬的贡献嘛/)
输入输出格式
输入描述:
输入由多个测试用例组成,每个测试用例是有两个非负整数m(总的精力),n的行作为第一行,然后后面有n行跟随,每行包括两个非负整数w[i],m[i],最后一个测试用例后面有一组 -1 -1(所有的整数都不大于1000,毕竟人类是有极限的嘛hhh)
输出描述:
对于每一个测试用例,在一行中输出吴大佬可以做出的题目数目,精确到小数点后3位
输入输出样例
输入样例:
233 6
6 1
23 66
32 23
66 66
1 5
8 5
-1 -1
输出样例:
136.000
思路分析:
这是很简单的贪心算法,想要做更多的题目的话,肯定优先选择性价比高的题目做,也就是说1题花费的精力最少的题目先做,因而去比较每个模块的题目1个题目所需要花费的精力是是多少,然后按照这个从低到高排序,一个个模块往下做即可。(这里注意模块内的题目是可以做部分的)
代码如下:
#include<bits/stdc++.h>
using namespace std;
struct T{
double num;
double power;
}p[1000];
bool compare(T a,T b){
return a.power/a.num<b.power/b.num;//比较性价比
}
int main(){
int m,n;
while(cin>>m>>n){
if(m==-1&&n==-1)
break;
for(int i=1 ; i<=n ; i++){
cin>>p[i].num>>p[i].power;
}
sort(p+1,p+1+n,compare);
double cnt=0;
for(int i=1 ; i<=n ; i++){
if(m>=p[i].power){//看看该模块的题目能不能全部做完
cnt+=p[i].num;
m-=p[i].power;
}
else{//不能全部做完的话就做一部分
cnt+=p[i].num*m/p[i].power;
break;
}
}
printf("%.3lf\n",cnt);
}
return 0;
}
二、To Fill or Not to Fill(浙大机试)
题目的翻译如下:
有了高速公路,开车从杭州到其他任何城市都很容易。但由于汽车的油箱容量是有限的,我们不得不不时地在路上找到加油站。不同的加油站可能会给出不同的价格。你被要求仔细设计最便宜的路线。
输入输出描述
输入描述:
对于每种情况,第一行包含4个正数:Cmax((= 100))表示油箱的最大容量;D(<=30000)表示杭州到目的地城市的距离;Davg(<=20)表示汽车每单位汽油行驶的平均距离;N(<= 500)为加油站总数。然后N行,每一行包含一对非负数:Pi,单位汽油价格,Di (<=D),该站到杭州的距离,i=l,…N。一行中的所有数字用一个空格隔开。
输出描述:
对于每个测试用例,在一行中打印最便宜的价格,精确到小数点后两位。假设油箱一开始是空的。如果不可能到达目的地,打印“最大旅行距离= X”,其中X是汽车可以运行的最大可能距离,精确到小数点后2位。
输入输出样例
输入样例:
50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300
50 1300 12 2
7.10 0
7.00 600
输出样例:
749.17
The maximum travel distance = 1200.00
思路分析:
首先在经过每个加油站时,都要确保油箱是满的。我们将不同加油站的油看成是一份加入到油箱中。利用双端队列维护油箱,双端队列的前端装价格低的油,后端装价格高的油。
在从加油站i-1驶向加油站i的过程中,优先使用队列前端的油,并进行价格的累加。每经过一个加油站,将该加油站的油价和队列中的油价进行对比,弹出队列中比该加油站价格高的油,然后用该加油站的油填满油箱剩余部分。
以上贪心策略保证了价格低的油可以最先被使用。另外需要注意的一点是,double类型的数字之间,由于精度问题,需要引入eps进行比较。
代码如下:
#include <stdio.h>
#include <deque>
#include <algorithm>
using namespace std;
#define eps 1.e-8
pair<double, double> g[505];//加油站<到杭州距离,一升汽油的价格>
int main() {
double cmax, d, davg;
int n;
while (scanf("%lf%lf%lf%d", &cmax, &d, &davg, &n) != EOF) {
for (int i = 0; i < n; i++)
scanf("%lf%lf", &g[i].second, &g[i].first);
g[n++] = make_pair(d, 0.);//终点也看作一个加油站,便于编码
sort(g, g + n);
deque<pair<double, double> > q;//模拟油箱<一升汽油的价格,该油的油量>
/*
sumDis:记录行驶路程
oil:记录油箱中剩多少油
cost:记录花费
*/
double sumDis = 0., oil = 0., cost = 0.;
if (g[0].first > eps) printf("The maximum travel distance = 0.00\n");
else {
q.push_back(make_pair(g[0].second, cmax));//在第一个加油站加满油
oil = cmax;
for (int i = 1; i < n; i++) {//从加油站i-1到i的过程
double gDis = g[i].first - g[i - 1].first;
double need = gDis / davg;
if (need > cmax + eps) {//油箱中的油不够
sumDis += (cmax * davg);
printf("%s%.2lf", "The maximum travel distance = ", sumDis);
printf("\n");
break;
}
else {
sumDis += gDis;
while (need >= eps) {//使用油箱中的油
double tmp = q.front().second;
if (tmp > need + eps) {
oil -= need;
cost += (need * q.front().first);
q.front().second -= need;
need = 0.;
}
else {
oil -= tmp;
cost += (tmp * q.front().first);
need -= tmp;
q.pop_front();
}
}
//给油箱加满油
if (q.empty()||q.back().first <= g[i].second - eps)
q.push_back(make_pair(g[i].second, cmax - oil));
else {
while (!q.empty()&&q.back().first > g[i].second + eps) {
oil -= q.back().second;
q.pop_back();
}
q.push_back(make_pair(g[i].second, cmax - oil));
}
oil = cmax;
if (i == n-1) printf("%.2lf\n", cost);
}
}
}
}
return 0;
}
贪心算法解题步骤:
①读懂题目的隐藏意思,抽象成数学模型
②找准排序的特征点,贪心算法一般是和sort函数一起用