大石头的搬运工(Lanqiao OJ 3829)

文章提供了C++代码来解决一个关于移动多堆石头的游戏问题,涉及计算前缀和和后缀和,找出最小总移动费用的算法实现。
摘要由CSDN通过智能技术生成

#前缀和 #STL #pair


问题描述

在一款名为”大石头的搬运工“的游戏中,玩家需要操作一排  n 堆石头,进行 n−1 轮游戏。。

每一轮,玩家可以选择一堆石头,并将其移动到任意位置。

在n−1 轮移动结束时,要求将所有的石头移动到一起(即所有石头的位置相同)即为成功。

移动的费用为石头的重量乘以移动的距离。例如,如果一堆重量为 2 的石头从位置 3 移动到位置 5 ,那么费用为 2 ×(5 - 3)= 4 .

请计算出所有合法方案中,将所有石头移动到一起的最小费用。

可能有多堆石头在同一个位置上,但是一轮只能选择移动其中一堆。


输入格式

第一行一个整数 n,表示石头的数量。

接下来  n  行,每行两个整数wi和pi,分别表示第 i  个石头的重量和初始位置。


输出格式

输出一个整数,表示最小的总移动费用。


样例输入

3
2 3
3 1
1 5

样例输出

8

说明:

一种最优的移动方式是:

首先,将第一个石头移动到位置  1,费用为 2 × ( 3 − 1) = 4 ;

然后,将第三个石头移动到位置  1,费用为  1 × ( 5 − 1 ) = 4 。

所以最小的总移动费用为  4 + 4 = 8 。


 数据范围

对于 20% 的测试样例,1 ≤ n ≤ 10^3;

对于 100% 的测试样例,1 ≤ n ≤ 10^5 , 1 ≤ wi,pi ≤ 10^6.


题解:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e5 + 10;

pair<int, int >p[N];
ll pre[N], nex[N];

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> p[i].second >> p[i].first;
	}
	sort(p + 1, p + n + 1);
	ll s = 0;
	for (int i = 1; i <= n; i++) {
		pre[i] = pre[i - 1] + s * (p[i].first - p[i - 1].first);
		s += p[i].second;
	}
	s = 0;
	for (int i = n; i >= 1; i--) {
		nex[i] = nex[i + 1] + s * (p[i + 1].first - p[i].first);
		s += p[i].second;
	}
	ll ans = 1e18;
	for (int i = 1; i <= n; i++) {
		ans = min(ans, pre[i] + nex[i]);
	}
	cout << ans << endl;

	return 0;
}

总结:

本题分别计算堆中任意一块石头的前后两部分各自的前缀和 pre[i] 和 nex[i] ,通过min找到最小的

定义了一个pair,用于存储石头的重量和位置两个信息,通过pair的 sort 排序功能 对石头的位置进行排序,便于后面计算前缀和时对距离的计算。

然后分别对pair中的每一个的石头计算 pre[i] ,和nex[i] 。

最后通过min找到最小的费用即可。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值