问题描述
•在一个操场的四周摆放着n堆石子,现要将石子有次序地合并成一堆。
•规定每次至少选2堆至多选k堆石子合并成新的一堆,合并的费用
为新的一堆石子数。
•计算出将n堆石子合并成一堆的最大总费用和最小总费用。
•对于给定的n堆石子,计算合并成一堆的最大总费用和最小总费用。
数据输入:文件的第1行有2个正整数n和k,表示有n堆石子,每次至少选2堆至多选k堆石子合并。
第2行有n个数,分别表示每堆石子的个数。
输入示例:
7 3
45 13 12 16 9 5 22
输出示例:
593 199
问题分析
-
N堆石子最少每次搬运两堆,最大不超过k堆,求最大搬运费用和最小搬运费用的问题。
-
所谓的最小花费即:每次尽可能多的搬运石子的堆数,但是搬运的每堆石子的个数要尽可能的少。
-
最大花费即,尽可能少的搬运石子的堆数,最少每次搬运两堆,并且尽肯能的搬运石子数多的堆。
重要提示
- 接下来的算法步骤我写的有
错误
- 错误原因是因为将选择的数组未进行重新排序
- 与能力的可以尝试修改完善此代码
- 这里附上正确的
**代码**
- 请点击跳转 正确代码的博客地址
算法步骤
1、 获取n(石子堆数),k(每次最大搬运堆数),stone数组(每堆石子的个数)
int n, k;//n-->多少堆,k-->最大每次移动多少堆
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
int[] stone = new int[n];
//输入每堆的石子个数
for (int i = 0; i < n; i++) {
stone[i] = sc.nextInt();
}
2、对stone数组进行排序
可以采用冒泡排序的方法,我是直接调用了java的方法
3、计算最大搬运石子费用
private static int maxfee(int[] stone) {
ArrayList<Integer> temp = new ArrayList<>();
int add = 0;//暂存两堆石子相加的结果
for (int i = stone.length - 1; i >= 0; i--) {
if (i == stone.length - 1) {
add = stone[i] + stone[--i];//--i先减再用
temp.add(add);//将相加的结果添加到temp数组中
} else {
temp.add(add + stone[i]);
add = add + stone[i];
}
}
int maxsum = 0;
for (Integer integer : temp) {
maxsum += integer;
}
return maxsum;
}
4、计算最小搬运费用
private static void minfee(int[] stone, int k) {
ArrayList<Integer> temp = new ArrayList<>();//临时变量temp记录移动后的每堆石子数量
for (int i = 0; i < stone.length; i++) {
int add = 0;//暂存两堆石子相加的结果
for (int j = 0; j < k; j++) {
if (i == stone.length) {//当循环的石子堆结束的时候跳出循环
break;
} else {
add += stone[i++];
}
}
if (add != stone[stone.length - 1])//若最后仅剩一堆,则这一堆没有参与搬运的操作,所以在这里直接计算minSum
minSum += add;
temp.add(add);
i--;//内层循环多加了一个1,所以这里要进行减一的操作
}
int[] diGui = new int[temp.size()];
for (int i = 0; i < diGui.length; i++) {
diGui[i] = temp.get(i);
}
if (temp.size() != 1) {//当前堆不为一堆的话递归
minfee(diGui, k);
}
}
完整代码
package cn.sg.test;
import java.util.ArrayList;
import java.util.Scanner;
import static java.util.Arrays.sort;
public class DuoYuanHaFuMan {
private static int minSum = 0;//记录最小花费
public static void main(String[] args) {
int n, k;//n-->多少堆,k-->最大每次移动多少堆
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
int[] stone = new int[n];
//输入每堆的石子个数
for (int i = 0; i < n; i++) {
stone[i] = sc.nextInt();
}
sort(stone);//调用java的方法对着n堆石子从小到大进行排序
int maxSum = maxfee(stone);//调用函数得到最大的费用
minfee(stone, k);//调用函数得到最小的消费
System.out.println(maxSum + "\t" + minSum);//对计算单数据进行输出
}
/**
* 计算得到最小的费用
*
* @param stone 当前的石头堆
* @param k 最大移动堆的数量
*/
private static void minfee(int[] stone, int k) {
ArrayList<Integer> temp = new ArrayList<>();//临时变量temp记录移动后的每堆石子数量
for (int i = 0; i < stone.length; i++) {
int add = 0;//暂存两堆石子相加的结果
for (int j = 0; j < k; j++) {
if (i == stone.length) {//当循环的石子堆结束的时候跳出循环
break;
} else {
add += stone[i++];
}
}
if (add != stone[stone.length - 1])//若最后仅剩一堆,则这一堆没有参与搬运的操作,所以在这里直接计算minSum
minSum += add;
temp.add(add);
i--;//内层循环多加了一个1,所以这里要进行减一的操作
}
int[] diGui = new int[temp.size()];
for (int i = 0; i < diGui.length; i++) {
diGui[i] = temp.get(i);
}
if (temp.size() != 1) {//当前堆不为一堆的话递归
minfee(diGui, k);
}
}
/**
* 计算最大费用
*
* @param stone 当前堆
* @return 返回最大费用
*/
private static int maxfee(int[] stone) {
ArrayList<Integer> temp = new ArrayList<>();
int add = 0;//暂存两堆石子相加的结果
for (int i = stone.length - 1; i >= 0; i--) {
if (i == stone.length - 1) {
add = stone[i] + stone[--i];//--i先减再用
temp.add(add);//将相加的结果添加到temp数组中
} else {
temp.add(add + stone[i]);
add = add + stone[i];
}
}
int maxsum = 0;
for (Integer integer : temp) {
maxsum += integer;
}
return maxsum;
}
}
运行截图
代码逻辑为个人思路,若有问题欢迎指正,谢谢🎈🎈