这道题目的在处理状态转移上面和我以前写过的一道题有点相似http://blog.csdn.net/good_night_sion_/article/details/52918040,这两个的思想是类似的,把一整个代价拆成一次次,然后累加
这道题目我用的是刷表法,为了计算代价的时候方便,采用了一个前缀和数组来储存delta。
状态的定义在之前也看到过,定义状态[i][j][k],表示i~j的区间走完现在处在k处(k==0在i,k==1在j)的最小代价。
区间每一次是向外延拓一个修缮点的,不可能去修理离区间有2个修缮点的地方,然后再返回来修。因为修理是不计时间的,与其先跑过去再回来,还不如去的时候就直接修掉,因此状态转移方程就很好的看出来了,在每一个状态下考虑向左走和向右走。
为了处理方便,我把起始点也看成了一个修缮点,不过这个修缮点的cost和delta都是0。
为什么在scanf后面不写==3就TLE呀!害得我找了好久!绝对数据最后有问题!
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cfloat>
using namespace std;
struct Node{
int dis,delta,cost;
Node(int a=0,int b=0,int c=0):dis(a),cost(b),delta(c){}
bool operator<(const Node& a)const{return dis<a.dis;}
}arr[1010];
int n,v,x,prefix[1010];
double dp[1010][1010][2];
int main(){
int te;
while(scanf("%d%d%d",&n,&v,&x)==3&&n){
for(int i=0;i<n;++i)
scanf("%d%d%d",&arr[i].dis,&arr[i].cost,&arr[i].delta);
arr[n]=Node(x);
sort(arr,arr+n+1);
prefix[0]=arr[0].delta;
for(int i=1;i<=n;++i)
prefix[i]=prefix[i-1]+arr[i].delta;
for(int i=0;i<=n;++i)
for(int j=0;j<=n;++j)
dp[i][j][0]=dp[i][j][1]=DBL_MAX;
for(int i=0;i<=n;++i)
if(arr[i].dis==x)
te=i,i=n;
dp[te][te][0]=dp[te][te][1]=0;
for(int length=1;length<=n;++length)
for(int i=0,j=i+length-1;j<=n;++i,++j){
if(dp[i][j][0]!=DBL_MAX){
if(i)
dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][0]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[i].dis-arr[i-1].dis)*1.0/v+arr[i-1].cost);
if(j<n)
dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][0]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[j+1].dis-arr[i].dis)*1.0/v+arr[j+1].cost);
}
if(dp[i][j][1]!=DBL_MAX){
if(i)
dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][1]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[j].dis-arr[i-1].dis)*1.0/v+arr[i-1].cost);
if(j<n)
dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][1]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[j+1].dis-arr[j].dis)*1.0/v+arr[j+1].cost);
}
}
printf("%.lf\n",floor(min(dp[0][n][0],dp[0][n][1])));
}
return 0;
}