和Mengjiji一起攻克难关
时间限制: C/C++ 1000ms; Java 2000ms 内存限制: 65535KB
通过次数: 11 总提交次数: 35
虽然const_bh的游戏造诣仅高于青铜六选手zbt,但是他的算法造诣也仅高于日常打铁的吃瓜群众zbt。但一日,const_bh偶有奇遇,遇到一位ACMdalao名曰Mengjiji,const_bh非常珍惜这次机会,于是和Mengjiji一起搞了一场比(p)赛(y)。
比赛共有n道题,每道题有一个难度值,比赛要求题目必须按顺序逐个去做,为了减轻的蒟蒻const_bh的压力,Mengjiji把原来的题目序列分成了两个序列,他和const_bh每人各负责一个序列的题目,已知每个人将要面对的挑战值为他所负责的序列的相邻两个数的差的绝对值的总和。Mengjiji身为dalao当然知道怎么分工使两个人的挑战值的和最小了,但是他想考一考const_bh,const_bh当然不会了,于是他偷偷的将这个问题用手机发给了聪明的你。
输入包括两行,第一行有一个n(n<=2000),代表题目的总数。
第二行有n个数,第i个数a[i]代表第i道题的难度值为a[i](0<=a[i]<=1000000000).
输出仅一行,一个数字代表两个人挑战值和的最小值。
5 1 2 1 3 4
2
将 【1,2,1,3,4】分成【1,1】和【2,3,4】两个序列,第一个序列的挑战值为0,第二个序列的挑战值为2.所以和为2.
思路:
规定dp[i][j](i>j)为A队列中最后一个元素的下标为i,B队列中最后一个元素的下标为j,时各相邻元素绝对值的最小和;
若只有两个元素,则结果为0;
n>2时可能有这么两种情况:
dp[i][i-1]:(相邻的两个元素分别放入两个队列中,在放入下标为i的元素时放到了与i-1不同的队列中),先初始化dp[i][i-1]=dp[i-1][0],再有dp方程dp[i][i-1]=min(dp[i][i-1],dp[i-1][j]+abs(a[i]-a[j]));j:0->i-2
dp[i][j]:(相邻的两个元素放入了同一个队列中,在放入下标为i的元素时放到了与i-1相同的队列中),有dp方程dp[i][j]=dp[i-1][j]+abs(a[i]-a[i-1]);j:0->i-2
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define me(x,y) memset(x,y,sizeof(x))
#define sd(x) scanf("%d",&x)
#define ss(x) scanf("%s",x)
#define sf(x) scanf("%f",&x)
#define slf(x) scanf("%lf",&x)
#define slld(x) scanf("%lld",&x)
#define pd(x) printf("%d\n",x)
#define plld(x) printf("%lld\n",x)
#define ps(x) printf("%s\n",x)
#define max(x,y) (x>=y?x:y)
#define min(x,y) (x<y?x:y)
#define sum(x,y) (x+y)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=2005;
ll a[maxn];
ll dp[maxn][maxn];
int n;
int main() {
sd(n);
for(int i=1;i<=n;i++) slld(a[i]);
if(n<=2) pd(0);
else {
dp[2][0]=abs(a[2]-a[1]);
for(int i=3;i<=n;i++) {
dp[i][i-1]=dp[i-1][0];
for(int j=0;j<=i-2;j++) {
dp[i][i-1]=min(dp[i][i-1],dp[i-1][j]+abs(a[i]-a[j]));
dp[i][j]=dp[i-1][j]+abs(a[i]-a[i-1]);
}
}
ll ans=maxv;
for(int i=0;i<n;i++)
ans=min(ans,dp[n][i]);
plld(ans);
}
return 0;
}