You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
4.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_01_4_week;
import java.util.ArrayList;
import java.util.LinkedList;
// 来自美团
// 小团去参加军训军训快要结束了长官想要把大家一排n个人分成m组然后让每组分别去参加阅兵仪式
// 只能选择相邻的人一组,不能随意改变队伍中人的位置
// 阅兵仪式上会进行打分,其中有一个奇怪的扣分点是每组的最大差值,即每组最大值减去最小值
// 长官想要让这分成的m组总扣分量最小即这m组分别的极差之和最小
// 长官正在思索如何安排中,就让小团来帮帮他吧
public class Code02_SplitToMArraysMinScore {
// public static int splitArrayMinScore(int[] arr, int k) {
// // arr[L...R]
// int[][] record = creatRecord(arr);
// return f(arr, arr.length - 1, k, record, .);
// }
//
//
//
// public static int[][] creatRecord(int[] arr) {
//
// // arr[L...R] 最大值 - 最小值 是多少?
// int n = arr.length;
// int[][] ans = new int[n][n];
// for() {
// for() {
//
// }
// }
//
// // ans[3][6] = arr[3...6] 最大值 - 最小值 是多少?
//
// }
//
// // arr[0......7] 8
// // arr[0...3] 4
// // arr[0..index] index + 1
// // arr[0....index]的数一定要分成part组
// // 返回最小的扣分量
// public static int f(int[] arr, int index, int part, int[][] record) {
// if (index + 1 <= part) {
// return 0;
// }
// // 数字的个数 > 划分部分的
// // 0...index part组
// // 0..7 3份
// // 最后一份,最右的一份: 7..7
// // 最后一份,最右的一份: 6..7 之前 0...5 2份
// // 最后一份,最右的一份: 5..7
// // 最后一份,最右的一份: 4..7
// // ...
// // 最后一份,最右的一份: 0..7
// int ans = Integer.MAX_VALUE;
// for (int rightTeamFirst = index; rightTeamFirst >= 0; rightTeamFirst--) {
// int rightTeamCost = record[rightTeamFirst][index];
// int preCost = f(arr, rightTeamFirst - 1, part - 1, record);
// int curAllCost = preCost + rightTeamCost;
// ans = Math.min(ans, curAllCost);
// }
// return ans;
// }
// 暴力方法
// 为了验证
public static int minScore1(int[] arr, int m) {
if (m == 0) {
return 0;
}
return process(arr, 1, m, arr[0], arr[0]);
}
public static int process(int[] arr, int index, int rest, int preMin, int preMax) {
if (index == arr.length) {
return rest == 1 ? (preMax - preMin) : -1;
}
int p1 = process(arr, index + 1, rest, Math.min(preMin, arr[index]), Math.max(preMax, arr[index]));
int p2next = process(arr, index + 1, rest - 1, arr[index], arr[index]);
int p2 = p2next == -1 ? -1 : (preMax - preMin + p2next);
if (p1 == -1) {
return p2;
}
if (p2 == -1) {
return p1;
}
return Math.min(p1, p2);
}
public static int score(ArrayList<LinkedList<Integer>> sets) {
int ans = 0;
for (LinkedList<Integer> set : sets) {
if (set.isEmpty()) {
return Integer.MAX_VALUE;
}
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int num : set) {
max = Math.max(max, num);
min = Math.min(min, num);
}
ans += max - min;
}
return ans;
}
// 正式方法
// 时间复杂度O(M * N * N)
// 特别难的一个结论 : 这道题不能利用四边形不等式,我试了
// 这个特别难的结论不要求必须掌握,因为四边形不等式的技巧非常冷门
public static int minScore2(int[] arr, int m) {
if (m == 0) {
return 0;
}
int n = arr.length;
int[][] score = new int[n][n];
for (int i = 0; i < n; i++) {
int max = arr[i];
int min = arr[i];
score[i][i] = max - min;
for (int j = i + 1; j < n; j++) {
max = Math.max(max, arr[j]);
min = Math.min(min, arr[j]);
score[i][j] = max - min;
}
}
int[][] dp = new int[m + 1][n];
for (int i = 0; i < n; i++) {
dp[1][i] = score[0][i];
}
for (int split = 2; split <= m; split++) {
for (int i = split; i < n; i++) {
dp[split][i] = dp[split - 1][i];
for (int j = 1; j <= i; j++) {
dp[split][i] = Math.min(dp[split][i], dp[split - 1][j - 1] + score[j][i]);
}
}
}
return dp[m][n - 1];
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = (int) (Math.random() * v);
}
return arr;
}
public static void main(String[] args) {
int len = 15;
int value = 50;
int testTime = 20000;
System.out.println("测试开始");
for (int i = 0; i < testTime; i++) {
int n = (int) (Math.random() * len) + 1;
int[] arr = randomArray(n, value);
int m = (int) (Math.random() * n) + 1;
int ans1 = minScore1(arr, m);
int ans2 = minScore2(arr, m);
if (ans1 != ans2) {
System.out.println("出错了!");
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
System.out.println("m : " + m);
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("测试结束");
}
}