uva 1336 - Fixing the Great Wall

//
//  main.cpp
//  uva 1336 - Fixing the Great Wall

/*
 我们先按位置大小排序。
 首先我们注意到:
 对于 i ....x.....j,x表示现在的机器人的位置。
 如果x现在在修复了i,那么位于x和i之间的所有位置都是已经修复好的了,因为我们当前已经到了i,那么我们就可以顺便修复了x和i之间的位置,这绝对不会增加最终的总费用。所以得出了一个结论。
 最优的修复顺序满足,1---x之间的位置在最优解中的相对位置是相反的。而x---n之间的位置的相对位置是不变的。
 
 有了这个结论我们可以想到解法了.
 对于当前的位置我们有两个选择 1.修复当前位置右边的位置。
                         2.修复当前位置左边的位置。
 
 设d[i][j][t]表示当前所在的位置为t,(t等于i或者j),且只考虑前i个,和第j个以及后面的位置,修理后面被破坏的区域需要的最少的钱。
 这里t只为1或者0.0表示在左边,1表示字右边的节点上。
 则有
 d[i][j][0] = min(d[i][j][0] , d[i-1][j][0]+t[i-1][i] * c_all[i-1][j],d[i-1][j+1][1] + t[j][j+1]* c_all[i-1][j+1]);t[i][j]表示从i到j的时间。
 同理可得出在t==1时的情况。
 */

#include <iostream>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<vector>
#include <string.h>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
#define ll long long
using namespace std ;
double d[1010][1010][2];
double v ;
double INF = 1000000000 ;
int c_all[1010][1010] ;
struct sec{
    int pos , c,d  ;
    bool operator < (const sec &temp ) const{
        return  pos < temp.pos ;
    } ;
};
sec wall[1010] ;
int n ;
double min(double  a,double b)
{
    return  a >b ? b :a ;
}
double dp(int l , int r , int t)
{
    if (d[l][r][t] >= 0  ) {
        return d[l][r][t] ;
    }
    else{
        double time  ;
        double& ans = d[l][r][t] ;
        ans = INF ;
        if (t == 0 ) {
            if (l <= 1&& r == n + 1) {
                return ans = 0 ;
            }
            if(l >1) {
                time =((double )(wall[l].pos - wall[l-1].pos))/v  ;
                ans = min(ans , dp(l-1,r , 0) + time * c_all[l-1][r]) ;
            }
            if(r <=n  ) {
                time = ((double) (wall[r].pos -  wall[l].pos))/v ;  ;
                ans = min(ans  , dp(l-1, r, 1) + time * c_all[l-1][r]) ;
            }
        }
        else{
            if (l == 0 && r == n ) {
                return ans = 0 ;
            }
            if(l >=1){
                time =((double )(wall[r].pos - wall[l].pos))/v  ;
                ans = min(ans , dp(l,r+1 , 0) + time * c_all[l][r+1]) ;
            }
            if(r <n  ){
                time = ((double) (wall[r+1].pos -  wall[r].pos))/v ;  ;
                ans = min(ans  , dp(l, r+1, 1) + time * c_all[l][r+1]) ;
            }
        }
        return ans ;
    }
}
int sum[1010] ;
int main() {
    int x,_v;
    double ans ;
    int cost ;
    while (scanf("%d%d%d" ,&n,&_v,&x)==3 &&  n + _v + x != 0 ) {
        cost = 0 ;
        for (int i = 0; i <  n ; i++) {
            scanf("%d%d%d" ,&wall[i+1].pos,&wall[i+1].c,&wall[i+1].d) ;
            cost += wall[i+1].c ;
        }
        sort(wall+1, wall+n+1) ;
        for (int i = 0; i <=n+5; i++) {
            for (int j = 0 ; j <= n +5; j++) {
                d[i][j][0] = d[i][j][1] = -1 ;
            }
        }
        sum[0] = 0 ;
        for (int i = 1; i <= n ; i++) {
            sum[i] = sum[i-1] + wall[i].d ;
        }
        for (int i  = 0; i <= n ; i++) {
            for (int j = i+1 ; j <=n; j++) {
                c_all[i][j] = sum[i] + sum[n] - sum[j-1] ;
            }
            c_all[i][n+1] = sum[i] ;
        }
        int s = 1 ;
        while (s <= n && wall[s].pos < x) {
            s++ ;
        }
        v = _v ;
        if (s == 1) {
            ans = dp(1, 2, 0) +(double(wall[1].pos - x) )/v*sum[n] ;
        }
        else if (s  ==n +1 )
        {
            ans = dp(n, n+1,0) +  (double(x- wall[n].pos) )/v*sum[n];
        }
        else{
            ans = min(dp(s-1, s , 0 ) +(double(x- wall[s-1].pos) )/v*sum[n] ,
                      dp(s-1, s , 1 ) +(double( wall[s].pos-x) )/v*sum[n]);
        }
        printf("%d\n" ,(int)(ans + 1e-8 +cost)) ;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值