一、原题回顾
* 给定一个3行n列的数组。需要从这n列中,每列中都选择一个数字出来,然后要求这组数据中,每相邻的两个元素的差的绝对值的累加和是最小的。输出最小的累加和即可。 * 输入示例:第一行为n的值,后面为数组。 * 5 * 5 9 5 4 4 * 4 7 4 10 3 * 2 10 9 2 3 * 这里可以选择[5, 7, 5, 4, 4],因为2 + 2 + 1 + 0 = 5。是最小的累加和。输出5即可。
二、思路回顾
其实拿到这个题目之后,第一反应肯定是一致的,就是dp,使用动态规划来做。甚至我都能想得到是通过一步步的局部最优解,然后得到最后的全局最优解。然而,最后实现起来的时候,却困难重重,再次印证了“紧张是写不出清晰的代码的”。哎,现在回头看,其实之前也做过一些dp,也十分清楚一旦dp,就最好设一个数组。结果当时竟然只想了设一个int [n] 大小的一位数组给dp,然后就陷入了困境。加上之后各种下标,把自己弄的晕乎乎的,哎,最后也没有做出来。
所以,后面一定要把dp的题目加强练习,特别是总结整理好思路,然后多练习,加强思路的快速实现。加油加油。
做题思路:建立和原数据一样大小的dp二维数组,除了第一列都初始化为0,后面的每一列中的第i行的元素,都代表在这一列选择第i行的这一个数字后,分别在前一行选择第0或者第1或者第2个数字,这三种情况中,可以获得的最小值。最后再从dp的最后一列中找最小值。
三、原题的解答。
import java.util.Scanner;
/**
* @Author: lei
* @Data: 2020.3.24 11:22
* @Description: 3.25阿里笔试题1
*/
public class AliTest1 {
public static void main(String [] args) {
//输入数据的处理
Scanner in = new Scanner(System.in); //列数
int n = in.nextInt();
int [][] a = new int[3][n]; //数据存放
for(int i = 0;i < 3;i++){
for(int j = 0;j < n;j++){
a[i][j] = in.nextInt();
}
}
int [][] dp = new int[3][n];
dp[0][0] = dp[1][0] = dp[2][0] = 0; //最开始的一行差值都设置为0
for(int i = 1;i < n;i++){
//dp[0][i]代表了:在第i列 选择了第0行的那个数字的情况下,可以获得的最小绝对值。(因此就要考虑三种情况:i-1行选择第0行或者第1行或者第2行的数字)
//在这三种情况中,既要算这三个数分别与 第i列第0行的那个数字 的差值的绝对值,还要加上它们各自对应的dp数组中的值,就是之前的局部最优解。
dp[0][i] = get_min(Math.abs(a[0][i-1]-a[0][i]) + dp[0][i-1], Math.abs(a[1][i-1]-a[0][i]) + dp[1][i-1],Math.abs(a[2][i-1]-a[0][i]) + dp[2][i-1]);
dp[1][i] = get_min(Math.abs(a[0][i-1]-a[1][i]) + dp[0][i-1], Math.abs(a[1][i-1]-a[1][i]) + dp[1][i-1],Math.abs(a[2][i-1]-a[1][i]) + dp[2][i-1]);
dp[2][i] = get_min(Math.abs(a[0][i-1]-a[2][i]) + dp[0][i-1], Math.abs(a[1][i-1]-a[2][i]) + dp[1][i-1],Math.abs(a[2][i-1]-a[2][i]) + dp[2][i-1]);
}
System.out.println(get_min(dp[0][n-1], dp[1][n-1], dp[2][n-1])); //最后再从末尾一行中的 三个dp值 中选择最小的那个。
}
//获取三个数中的最小值
public static int get_min(int a, int b, int c){
return Math.min(a, Math.min(b, c));
}
}