贪心算法(浙大机试)

一、组队刷题(先来道简单的)

某天,吴大佬准备和菜鸡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函数一起用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值