codevs1427 特种部队

题目描述 Description

某特种部队接到一个任务,需要潜入一个仓库。该部队士兵分为两路,第一路士兵已经在正面牵制住了敌人,第二路士兵正在悄悄地从后方秘密潜入敌人的仓库。
当他们到达仓库时候,发现这个仓库的锁是一把很诡异的电子锁,上面是一排按钮,每个按钮上都有一个数字。10 秒钟后,总部返回了该锁的技术信息。要解开这把锁,首先要从左边的第一个按钮开始向右按动,中间可以跳过某些按钮,按动到最右边的按钮后,反向向左按动。最终,每个按钮都要按且仅按一次。每两个相邻按钮上数字之差的总和的最小值,便是解开这把锁的密码。
作为一支装备精良的特种部队,必须要在最短的时间内完成任务,解开这把锁,潜入仓库。

输入描述 Input Description

第一行是一个n(2 <= n <= 1000)表示共有n 个按钮。
第二行是n 个正整数,代表从左至右各按钮上的数字,数值均不超过2000。

输出描述 Output Description

只有一个数,为这把锁的密码。

样例输入 Sample Input

5
1 2 3 4 5

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

2 <= n <= 1000,数值不超过2000

分析:

动态规划的题目。

可以将它看作是两条路同时从最后的那个点往回走(即两条路起点相同,终点不同,且除了最后一点之外,两条路不能经过相同的一点),因此为了便于计算和理解,我们在最初存储数组的时候倒着存储数据,这样两条路都从最前面开始了。

利用二维数组dp[i][j]来进行动归求解,dp[i][j]碉堡两条路分别到达i和j( i > j ),并且从1至i的所有点都经过了,为了更加直观一点,我们假设两条路分别为A和B,假设在一个状态下,A走到i,B 走到 j ,则可以推断出下面状态:

状态1:A上一步就在B的前面(此时B的位置 < i-1),现在A又往前面走了一步(从 i-1 走到 i)。

状态2:A上一步在B的后面(此时A所在的位置 < i-1), 因为i>j,则B在 i -1 位置不变,这一步A超过了B(从 < i-1 走到 i )

代码如下:

public class DPTesr{

  public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    System.out.println("请输入按钮数量:");
    int n = scanner.nextInt();
    System.out.println("请输入各按钮数字(数字间空格隔开):");
    scanner.nextLine();
    String[] numStr = scanner.nextLine().trim().split(" ");
    int[] numArr = new int[n+1];
    //倒着存储
    for (int i = n; i > 0; i--){
      numArr[i] = Integer.parseInt(numStr[i-1]);
    }
    scanner.close();
    //状态存储
    int[][] dp = new int[n+1][n+1];
    //初始化
    for (int i = 0; i <= n; i++){
      for (int j = 0; j <= n; j++){
        dp[i][j] = 0x3f3f3f3f;
      }
    }
    dp[1][1] = 0;
    dp[1][2] = Math.abs(numArr[2]-numArr[1]);
    dp[2][1] = Math.abs(numArr[2]-numArr[1]);
    int ans = 0x3f3f3f3f;
    //从3开始j能存在
    for (int i = 3; i <= n; i++){
      for (int j = 1; j < i-1; j++) {
        //上一步A走在前面的继续往前走的场景(i>j)
        dp[i][j] = Math.min(dp[i][j], dp[i-1][j]+Math.abs(numArr[i]-numArr[i-1]));
        //上一步B走在前面的继续往前走的场景(i>j)
        dp[j][i] = Math.min(dp[j][i], dp[j][i-1]+Math.abs(numArr[i]-numArr[i-1]));
        //上一步B落后在后面的超过前面A的场景(1到i到点都走过了,在B落后超前都场景中,超前后的位置A在i-1位置,B则在i的位置)
        dp[i-1][i] = Math.min(dp[i-1][i], dp[j][i-1]+Math.abs(numArr[i]-numArr[j]));
        //上一步A落后在后面的超过前面的B场景(1到i到点都走过了,在A落后超前都场景中,超前后的位置B在i-1位置,超前后A则在i的位置)
        dp[i][i-1] = Math.min(dp[i][i-1], dp[i-1][j]+Math.abs(numArr[i]-numArr[j]));
      }
    }
    //只要有其中一个走到末尾就可以得到答案
    for (int k = 1; k <= n; k++){
      ans = Math.min(ans, dp[k][n]);
    }
    System.out.println(ans);
  }

}

题目来源:http://codevs.cn/problem/1427/ 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值