UVA1336 Fixing the Great Wall【区间DP&&记忆化搜索】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/83097086

Time limit 3000ms
在这里插入图片描述


题目大意

长城上有N个地点要修补,给定每个点的位置、初始修复成本,每单位时间增加的成本
给定修补机器人 初始位置及移动速度
求机器人如何移动使得总成本最小


题目分析

将这N个点按位置排序
显然如果一个点走过他再回头修一定不会最优
所以任意时刻已修补的区间一定是连续的
即若当前以修好第 l l ll ~ r r rr 个地点,那么下一个修补的一定是 l l 1 ll-1 r r + 1 rr+1

定义 d p [ l l ] [ r r ] [ 0 / 1 ] dp[ll][rr][0/1] 表示已经修好了 [ l l , r r ] [ll,rr] 区间的地点,且当前所在位置为 l l ( 0 ) ll(0) 还是 r r ( 1 ) rr(1)
修补完剩下的地点所需最小化费

初始化 d p [ 1 ] [ n ] [ 0 ] = d p [ 1 ] [ n ] [ 1 ] = 0 dp[1][n][0]=dp[1][n][1]=0 ,其余为INF
状态转移方程
W = S u m [ n ] ( S u m [ r r ] S u m [ l l 1 ] ) W=Sum[n]-(Sum[rr]-Sum[ll-1]) 及计算剩余没修补的地点每单位时间增加的成本总和
d p [ l l ] [ r r ] [ 0 ] = m i n ( d p [ l l 1 ] [ r r ] [ 0 ] + L e n ( l l 1 , l l ) / V W , d p [ l l ] [ r r + 1 ] [ 1 ] + L e n ( l l , r + 1 ) / V W ) dp[ll][rr][0]=min(dp[ll-1][rr][0]+Len(ll-1,ll)/V*W,dp[ll][rr+1][1]+Len(ll,r+1)/V*W)
d p [ l l ] [ r r ] [ 1 ] = m i n ( d p [ l l 1 ] [ r r ] [ 0 ] + L e n ( l l 1 , r r ) / V W , d p [ l l ] [ r r + 1 ] [ 1 ] + L e n ( r r , r + 1 ) / V W ) dp[ll][rr][1]=min(dp[ll-1][rr][0]+Len(ll-1,rr)/V*W,dp[ll][rr+1][1]+Len(rr,r+1)/V*W)

注意这里我们还要把机器人的初始位置作为一个点加进去,所以总点数应为N+1
设排序后表示机器人的点为K,从DP(k,k,0)开始记搜即可
答案为 d p [ k ] [ k ] [ 0 ] + S U M dp[k][k][0]+SUM (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;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/83097086