题目大意:
现在一条直线上有n个人,告诉你每个人的位置,现在让你从给定位置出发,经过这n个位置,每个位置有一个对应的不悦值,一开始都为0,第i个位置每过一分钟增加vi的不悦值,现在让你求出经过所有点能得到的最小不悦值为多少。
分析:
从起始点开始,决策是什么?当然是每一步都有可能去找当前位置左边的第一个或者右边的第一个,我们优化的就是这个决策。
所以想到dp:
**dp(i,j,1)表示经过完第i个和第j个然后站在j号位置产生的不悦值。
dp(i,j,1)表示经过完第i个和第j个然后站在i号位置产生的不悦值。**
不过这个边界实在太难确定了,20分钟写完,调整边界又调整了一上午,还好1A了。。。。
代码:
#include<bits/stdc++.h>
#define maxn 1050
using namespace std;
int n,t,x,dp[maxn][maxn][2],sum[maxn][maxn];
struct point
{
int v;int x;int flag;
}a[maxn];
bool cmp(point x,point y)
{
return x.x<y.x;
}
void init()
{
memset(dp,-1,sizeof(dp));
dp[x][x][1]=0;dp[x][x][0]=0;
for(int i=0;i<=n;i++)sum[i][i]=a[i].v;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=n-i;j++)
{
sum[j][j+i]=sum[j][j+i-1]+a[j+i].v;
//printf("sum[%d][%d]=%d\n",j,i+j,sum[j][i+j]);
}
}
}
int f(int l,int r,int k)
{
if(dp[l][r][k]!=-1)
{
//printf("f(%d,%d,%d)=%d\n",l,r,k,dp[l][r][k]);
return dp[l][r][k];
}
if(k==0)
{
int vv=((l==0)?0:sum[0][l-1])+sum[r][n];
//cout<<vv<<endl;
if(l==x)
{
int rr=f(l,r-1,0)+abs(a[r].x-a[r-1].x)*t*vv;
dp[l][r][k]=rr;
}
else
{
if(r==x+1)
{
int ll=f(l,r-1,1)+abs(a[l].x-a[r].x)*t*vv;
dp[l][r][k]=ll;
}
else
{
int ll=f(l,r-1,1)+abs(a[l].x-a[r].x)*t*vv;
int rr=f(l,r-1,0)+abs(a[r].x-a[r-1].x)*t*vv;
dp[l][r][k]=min(ll,rr);
}
}
}
else
{
int vv=((r==n)?0:sum[r+1][n])+sum[0][l];
if(r==x)
{
int ll=f(l+1,r,1)+abs(a[l].x-a[l+1].x)*t*vv;
dp[l][r][k]=ll;
}
else
{
if(l==x-1)
{
int rr=f(l+1,r,0)+abs(a[r].x-a[l].x)*t*vv;
dp[l][r][k]=rr;
}
else
{
int rr=f(l+1,r,0)+abs(a[r].x-a[l].x)*t*vv;
int ll=f(l+1,r,1)+abs(a[l].x-a[l+1].x)*t*vv;
dp[l][r][k]=min(ll,rr);
}
}
}
//printf("f(%d,%d,%d)=%d\n",l,r,k,dp[l][r][k]);
return dp[l][r][k];
}
int main()
{
while(scanf("%d%d%d",&n,&t,&a[0].x)!=EOF)
{
a[0].flag=1;a[0].v=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].v);a[i].flag=0;
}
sort(a,a+n+1,cmp);
for(int i=0;i<=n;i++)
{
if(a[i].flag==1)
{
x=i;break;
}
}
init();
if(x==0)
{
printf("%d\n",f(0,n,0));continue;
}
if(x==n)
{
printf("%d\n",f(0,n,1));continue;
}
int l=f(0,n,1),r=f(0,n,0);
printf("%d\n",min(l,r));
}
}