版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/83097086
Time limit 3000ms
题目大意
长城上有N个地点要修补,给定每个点的位置、初始修复成本,每单位时间增加的成本
给定修补机器人 初始位置及移动速度
求机器人如何移动使得总成本最小
题目分析
将这N个点按位置排序
显然如果一个点走过他再回头修一定不会最优
所以任意时刻已修补的区间一定是连续的
即若当前以修好第
~
个地点,那么下一个修补的一定是
或
定义
表示已经修好了
区间的地点,且当前所在位置为
还是
修补完剩下的地点所需最小化费
初始化
,其余为INF
状态转移方程
令
及计算剩余没修补的地点每单位时间增加的成本总和
注意这里我们还要把机器人的初始位置作为一个点加进去,所以总点数应为N+1
设排序后表示机器人的点为K,从DP(k,k,0)开始记搜即可
答案为
(SUM为初始成本总和)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef double dd;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int inf=1e9;
const int maxn=1010;
int n,v,x;
struct node{dd pos,c,dt;}rem[maxn];
bool cmp(node a,node b){return a.pos<b.pos;}
dd sum[maxn],dp[maxn][maxn][2];
dd DP(int ll,int rr,int d)
{
if(ll==1&&rr==n+1) return 0;
if(dp[ll][rr][d]!=inf) return dp[ll][rr][d];
dd resl=0,resr=0,ss=sum[n+1]-(sum[rr]-sum[ll-1]);
if(ll>1){
if(d==1) resl=(rem[rr].pos-rem[ll-1].pos)/v*ss;
else resl=(rem[ll].pos-rem[ll-1].pos)/v*ss;
}
if(rr<=n){
if(d==1) resr=(rem[rr+1].pos-rem[rr].pos)/v*ss;
else resr=(rem[rr+1].pos-rem[ll].pos)/v*ss;
}
if(ll>1) dp[ll][rr][d]=min(dp[ll][rr][d],DP(ll-1,rr,0)+resl);
if(rr<=n) dp[ll][rr][d]=min(dp[ll][rr][d],DP(ll,rr+1,1)+resr);
return dp[ll][rr][d];
}
int main()
{
while(scanf("%d%d%d",&n,&v,&x)!=EOF)
{
if(n==0&&v==0&&x==0) break; dd ssum=0;
for(int i=1;i<=n;++i)
scanf("%lf%lf%lf",&rem[i].pos,&rem[i].c,&rem[i].dt);
rem[n+1].pos=x; rem[n+1].c=0; rem[n+1].dt=0;//将机器人也作为一个点加入
sort(rem+1,rem+2+n,cmp);
for(int i=1;i<=n+1;++i)
ssum+=rem[i].c,
sum[i]=sum[i-1]+rem[i].dt;
for(int i=1;i<=n+1;++i)
for(int j=1;j<=n+1;++j)
dp[i][j][0]=dp[i][j][1]=inf;
for(int i=1;i<=n+1;++i)
if(rem[i].pos==x){ printf("%.0lf\n",floor(DP(i,i,0)+ssum)); break;}
}
return 0;
}