一、题目
有n种类的果子,每个果子重量均为1。每一种类各有不同数量的果子,由输入决定该数量,每一类果子堆一堆。果农需要通过搬运把所有果子合并,每一次搬运合并两堆果子,直到只剩一堆,共需要搬运n-1次。每次搬运消耗的体力是两堆果子的重量之和。求最少搬运体力。
https://www.lanqiao.cn/problems/741/learning/
二、分析
搬运n-1次,每次需要找出最轻的两堆果子,然后计算体力。接着两堆果子的重量之和需要作为一堆新的果子看待,重回搬运数组中参与下一轮搬运。直到只剩一堆。
算法:贪心算法,或者优先队列
三、代码
运用数组weight代表果子重量,数组move代表果子是否已经搬运。
#include <iostream>
#include <cmath>
using namespace std;
int indiff = pow(2,31);
int main() {
int n; // 种类
cin >> n;
while (n < 1 || n > 10000) {
cout << "n的范围需要在1~10000(包含)以内,请重新输入:";
cin >> n;
}
// 不同种类果子的重量
//vector<int> weight;
int* weight = new int[n];
bool* move = new bool[n]; // 果子是否已经搬运
for (int i = 0; i < n; i++) {
cin >> weight[i];
while (weight[i] >= pow(2, 31)) {
cin >> weight[i];
}
move[i] = 0;
}
int consume = 0; // 耗费体力
int min_1, min_2; // 最小的两堆果子的重量
min_1 = indiff;
min_2 = indiff;
int index_1 = 0, index_2 = 0; // 对应下标
for (int i = 0; i < n - 1; i++) { // n-1次合并
for (int j = 0; j < n; j++) { // n次比较,找出最小值
if (move[j])
continue;
else if (weight[j] < min_1) { // 未搬运,且最小
min_2 = min_1;
index_2 = index_1;
min_1 = weight[j];
index_1 = j;
}
else if (weight[j] < min_2) {
min_2 = weight[j];
index_2 = j;
}
}
// 搬运合并
consume = consume + min_1 + min_2;
weight[index_1] = min_1 + min_2;
move[index_2] = true;
min_1 = indiff;
min_2 = indiff;
}
cout << consume;
}