特种部队
时间限制: 1 s
空间限制: 64000 KB
题目描述 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
题目分析:首先题目要求来回两次选数,这个来回非常恶心,所以我们可以考虑把题目转化为从终点开始,向起点选两次数。
状态设计:设dp[i][j]为当前两次选数分别选到i点和j点的最小答案,且min(i,j)到n的数都被选过一次。
状态转移:状态设计出来,转移就比较简单了,每次(i,j)只会向(min(i,j)-1,j)和(i,min(i,j)-1)转移。
#include<bits/stdc++.h> #define N 2005 using namespace std; int a[N]; int dp[N][N]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=0;i<=n+1;i++) for(int j=0;j<=n+1;j++)dp[i][j]=INT_MAX/2; dp[n][n]=0; for(int i=n;i>=1;i--) for(int j=n;j>=1;j--) { if(min(i,j)-1!=j&&min(i,j)>1) { dp[min(i,j)-1][j]=min(dp[min(i,j)-1][j],dp[i][j]+abs(a[i]-a[min(i,j)-1])); // dp[min(i,j)-1][j]=min(dp[min(i,j)-1][j],dp[i][j]+abs(a[j]-a[min(i,j)-1])); } if(min(i,j)-1!=i&&min(i,j)>1) { // dp[i][min(i,j)-1]=min(dp[i][min(i,j)-1],dp[i][j]+abs(a[i]-a[min(i,j)-1])); dp[i][min(i,j)-1]=min(dp[i][min(i,j)-1],dp[i][j]+abs(a[j]-a[min(i,j)-1])); } } int ans=INT_MAX/2; for(int i=1;i<=n;i++)ans=min(ans,dp[1][i]),ans=min(ans,dp[i][1]); printf("%d ",ans); return 0; }