区间dp,~~~~
dp[i][j][0]表示i到j之间已经走过,并且现在在i点的staleness(可以理解为枯萎指数)最小值,
dp[i][j][1]表示i到j之间已经走过,并且现在在j点的staleness最小值。
于是对于在i点,可能从i+1->i,也可能从j->i,即:
很重要的一点,在我们转移到i时,除了即将到达的i点,还有未到达的(n-(j-i+1))个点,即总共(n-(j-i))个点,它们的枯萎指数均在增加,so~
dp[i][j][0]=min(dp[i+1][j][0]+(n-(j-i))*(pos[i+1]-pos[i]),dp[i+1][j][1]+(n-(j-i))*(pos[j]-pos[i]));
同理对于当前在j点,也可以得到向相应的方程:
dp[i][j][1]=min(dp[i][j-1][1]+(n-(j-i))*(pos[j]-pos[j-1),dp[i][j-1][0]+(n-(j-i))*(pos[j]-pos[i])).
最后需要注意的就是初始话的问题了,找到L在原序列中的位置就好。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
题目链接:http://poj.org/problem?id=3042
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000+10
using namespace std;
int p[N];
int f[N][N][2];
int main()
{
int n,s;
while(~scanf("%d%d",&n,&s))
{
int ok=1;
for(int i=0;i<n;i++)
{
scanf("%d",&p[i]);
if(p[i]==s) ok=0; //可能存在某点与起点重合的情况。
}
if(ok) p[n++]=s;
sort(p,p+n);
int pos=lower_bound(p,p+n,s)-p; //二分查找L的位置。
memset(f,0x3f,sizeof(f));
f[pos][pos][0]=f[pos][pos][1]=0; //起点~
for(int i=pos;i>=0;i--)
{
for(int j=pos;j<n;j++)
{
f[i][j][0]=min(f[i][j][0],f[i+1][j][0]+(n-(j-i))*(p[i+1]-p[i]));
f[i][j][0]=min(f[i][j][0],f[i+1][j][1]+(n-(j-i))*(p[j]-p[i]));
f[i][j][1]=min(f[i][j][1],f[i][j-1][1]+(n-(j-i))*(p[j]-p[j-1]));
f[i][j][1]=min(f[i][j][1],f[i][j-1][0]+(n-(j-i))*(p[j]-p[i]));
}
}
printf("%d\n",min(f[0][n-1][0],f[0][n-1][1]));
}
return 0;
}