楼间跳跃----贪心复习

【题目描述】
在一条街道上有n栋楼,第i栋有hi层,每层都有价值为vi的物品。Lyra可以花费一单位时间在同一栋楼中向上或向下走一层。特别地,每栋楼里都有一个大滑梯,只能从顶楼通往一楼,所以如果Lyra在顶层,可以花费一单位时间通过滑梯到达一楼(注意只有在顶楼才可以使用滑梯)。

Lyra还可以在不同的楼之间跳跃,即花费一单位时间从当前楼移动到相邻楼的同层,如果相邻楼没有Lyra当前位置高,则会落到相邻楼的顶层。

初始时Lyra在第一栋楼的顶层,她有m单位时间可以移动,Lyra拿去物品不需要时间,且一个物品被拿一次之后就会消失。Lyra想知道她能获得的总价值最多是多少?
【输入】
第一行两个正整数n,m
以下n行每行两个整数表示hi和vi

提示:输入数据较大,请采用快速的读入方式。
【输出】

输出一行一个整数表示最大的总价值。
【输入样例】

3 3
2 1
1 5
3 4

【输出样例】

14

解题思路:

核心思想是怎样求最大值,这里是按着第一栋,第1,2栋,第1,2,3栋的顺序,
先是只在第一栋楼里活动,然后判断时间是否超过;
当第2,3栋的时候,如果第二栋的价值比第一栋的大,这就要考虑要不要把第一栋全部换为第二栋(这里考虑换的时候还有两种情况:即是可以全部换,还是只需换一部分);
第1,2,3栋的时候亦是如此。
可以参考下鱼塘钓鱼的题目
没想到第一篇题解竟是这么难的题,qwq
#include
using namespace std;
#define ll long long
#define val first
#define high second
priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>>que;
ll n, m;
const int M = 1000000;
ll h[M + 5], v[M + 5];
int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> h[i] >> v[i];
		h[i]--;//每一楼的第一个是不用花时间的
		//即如第一栋有7层,从顶层到底层只需7-1个单位时间
	}
	
	ll sum = 0;
	ll ans = 0;
	ll maxn = 0;
	for (int k = 1; k <= n; k++) {
		//按着第一栋,第一栋和第二栋,第1,2,3栋的顺序来
		ans += v[k];//在这一栋楼,如第2栋,就直接加上价值,跳到这楼上的时候
		if (sum + h[k] <= m) {//此时没有取满,就直接加上
			//此时的第二栋的h[i]已经-1,上面加了			
			sum += h[k];//时间
			ans += h[k] * v[k];
			que.push(make_pair(v[k], h[k]));
		}//注意,这里如果没满的话,直接进入到下一层循环,如题目中的
		//第二栋只需一次即可。
		else {//当此时已经超过时间,就要判断没有加的
			//楼和前面已加的楼的方案
			pair<ll, ll>a;
			a = que.top();
			while (a.val < v[k] && (!que.empty())) {
				//如果前一栋楼的数值比现在的小,则把前面一栋的全部换掉(最好)
				if (sum + h[k] - a.high >= m) {//如果我把前面的
					//一栋楼用现在的楼代替还大于m
					//说明要跟其前前面的楼比较
					//把之前的楼删掉
					que.pop();
					ans = ans - a.high * a.val;
					sum -= a.high;
				}
				else {//如果全部替换后还有多于的时间
					//就说明之前的楼只需要丢掉一部分使
					//新加的刚好等于m
					que.pop();
					int mid = sum + h[k] - m;//看多出了几层
					ans = ans - mid * a.val;	//减去多出的层数
					a.high -= mid;
					sum -= mid;
					que.push(a);
					break;
				}
				a = que.top();
			}
			int mark = m - sum;	//求出需要填充几层
			pair<ll, ll>q;
			q.val = v[k];
			q.high = mark;
			if (q.high) {
				que.push(q);
				ans = ans + q.val * q.high;
				sum = m;
			}
		}
		if (ans > maxn)
			maxn = ans;
		m--;	//每次到下一栋楼就要花费1个单位时间
	}
	cout << maxn;
	return 0;
}

这题主要运用了贪心算法,虽然不是几个典型的题,但也算是经典,这题也是类似的就只是题解多了点。楼间跳跃这题我好像只找到了2篇,算上我这一篇,我还是借鉴于(https://blog.csdn.net/stldecember/article/details/93976721)。

最后附上贪心算法的讲解:五大常用算法入门–贪心算法

你可能感兴趣的:(楼间跳跃----贪心复习)