首页 > 技术文章 > Codevs 1427 特种部队(双路DP)

nancheng58 2016-08-03 07:13 原文

1427 特种部队
时间限制: 1 s
空间限制: 64000 KB
题目等级 : 黄金 Gold
题目描述 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
分类标签 Tags
动态规划

/*
双路DP.
f[i][j]表示第一路扩展到i,第二路扩展到j的最优值.
对于max(i,j)后的一点k扩展 
(1~max(i,j)可以看做是被两路分成的两段不连续序列)
则:f[i][k]=min(f[i][k],f[i][j]+s[j][k]);//2路.
   f[k][j]=min(f[k][j],f[i][j]+s[i][k]);//1路.
最后枚举一个所谓的断点i求出贡献(因为不确定n点在哪一路). 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath> 
#define MAXN 1001
using namespace std;
int n,ans=1000000001,s[MAXN][MAXN],a[MAXN],f[MAXN][MAXN];
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
    return x*f;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        s[i][j]=abs(a[j]-a[i]);
    memset(f,127/3,sizeof(f));
    f[0][0]=0;
    for(int i=0;i<=n;i++)
      for(int j=0;j<=n;j++){
        int k=max(i,j)+1;
        f[i][k]=min(f[i][k],f[i][j]+s[j][k]);
        f[k][j]=min(f[k][j],f[i][j]+s[i][k]);
      }
    for(int i=0;i<=n;i++)
      ans=min(ans,f[i][n]+s[i][n]),ans=min(ans,f[n][i]+s[i][n]);
    printf("%d",ans);
    return 0;
}

推荐阅读