您的位置:首页 > 其它

Uva1336 修长城 【有关未来费用的区间dp】

2017-07-05 16:08 429 查看

题外话

此题简化版:codevs1258/洛谷P1220

此题(伪)升级版:送披萨(可以选择送给这个人或者不送)

题目大意中的题目背景属于报复行为,大家无视即可。

题目大意

邪恶的魔王jyf用厉害的膜法在长城上制造了n个破坏点,正义的守护者boshi此时正处于x处,他急忙准备去修复长城。对于每个破坏点,boshi站在这个破坏点前面,然后用修复膜法瞬间修复,但是需要花费一些体力,并且由于jyf的膜法狠厉害,所以每过1s,破坏就会增大,所以实际上boshi在第ts修复点i的花费体力为ci+t*di,而boshi开着小电驴的移动速度为v。由于boshi很懒,他不想花太多体力,所以请你帮他求出他修好长城要花多少体力?

题目分析

首先,对于一段连续的区间[l,r],boshi是如此的大佬以至于他不会走出这个区间修几个点然后再溜达回来修完,所以boshi每一步修的区间一定是连续的,那么boshi在修完这个区间后,他要么在区间最左端,要么在最右端,那么我们可以用f(l,r,t)表示boshi修[l,r]区间的花费体力,其中当t=1时boshi在最右端,否则在最左端。

那么当boshi在最左端的时候,他肯定已经修复了[l+1,r]这个区间,修复这个区间后是在左还是在右就是决策,然后花费便是boshi从[l+1,r]这个区间走到l位置的时间里,所有没修复的(不在区间[l+1,r]中的)破坏点的t*di值的增大值。在最右端同理。

用记忆化搜索解决。

注意l==r的情况。

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<climits>
#include<cmath>
#include<algorithm>
using namespace std;
int n;double v,u;
struct node{double x,c,d;}p[1005];
double f[1005][1005][2],sum[1005];
bool cmp(node a,node b){return a.x<b.x;}
double dp(int l,int r,int t){//0:在左边,1:在右边
if(f[l][r][t]!=-1)return f[l][r][t];
if(l==r){
f[l][r][t]=fabs(u-p[l].x)/v*sum
+p[l].c;
return f[l][r][t];
}
if(!t){
double tot=sum
-sum[r]+sum[l];
f[l][r][t]=dp(l+1,r,0)+tot*(p[l+1].x-p[l].x)/v+p[l].c;
f[l][r][t]=min(f[l][r][t],dp(l+1,r,1)+tot*(p[r].x-p[l].x)/v+p[l].c);
}
else {
double tot=sum
-sum[r-1]+sum[l-1];
f[l][r][t]=dp(l,r-1,1)+tot*(p[r].x-p[r-1].x)/v+p[r].c;
f[l][r][t]=min(f[l][r][t],dp(l,r-1,0)+tot*(p[r].x-p[l].x)/v+p[r].c);
}
return f[l][r][t];
}
int main()
{
int i,j,k;double c;
while(scanf("%d%lf%lf",&n,&v,&u)==3&&n){
for(i=1;i<=n;i++)scanf("%lf%lf%lf",&p[i].x,&p[i].c,&p[i].d);
n++;p
.x=u;p
.c=p
.d=0;
sort(p+1,p+1+n,cmp);
for(i=1;i<=n;i++)sum[i]=sum[i-1]+p[i].d;
for(i=1;i<=n;i++)for(j=i;j<=n;j++)f[i][j][1]=f[i][j][0]=-1;
printf("%.0lf\n",floor(min(dp(1,n,1),dp(1,n,0))));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: