UVa1336 Fixing the Great Wall

UVa1336 - Vjudge

  • 题目大意
    用机器人修复分布在一条直线段上的n个坏点,对于每个点i,x[i]表示位置,c[i]为立刻修缮的费用,d[i]为单位时间增加的维修费用。例如若在时刻t修缮i号点,则费用为 ci+tdi 。给出机器人的初始位置x,速度v。求出修缮所有点的最小费用。

  • 题解
    f[i][j][k]为修复完i~j,当前位置在k(k为0则在x[i],为1则在x[j])之后所有的费用。可以用Color Length这道题的思路,即转移时每走一单位时间,就把这一单位时间中为修缮的点所产生的费用全部累加起来。具体转移方法如下:
    往左走,则转移到f[i-1][j][0],若当前位置为now,从now走到x[i-1]所需要的时间为t,则
    f[i][j][k]=f[i1][j][0]+(sumd(1,i1)+sumd(j+1,n))t+c[i1]
    往右走同理

//UVa1336 By KikiDMW
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<memory>
#include<vector>
#include<deque>
#include<cmath>
#include<ctime>
#include<queue>
#include<list>
#include<map>
#include<set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define F(i,j,n) for(register int i=j;i<=n;i++)
#define D(i,j,n) for(register int i=j;i>=n;i--)
#define ll long long
#define db double
#define lc(k) (k<<1)
#define rc(k) ((k<<1)|1)
using namespace std;

const int N = 1000 + 10;
const db inf = 1e30;
struct Node{
    db x, c, d;
    bool operator < (const Node &n) const{
        return x < n.x;
    }
}a[N];
int n, vis[N][N][2], kase;
db v, x, f[N][N][2], s, pre[N], ans;

void init(){
    s = 0.0; pre[0] = 0.0; ans = inf;
    for(int i = 1; i <= n; i++){
        scanf("%lf%lf%lf", &a[i].x, &a[i].c, &a[i].d);
        s += a[i].c; //先记录下初始必花的费用 
    }
    sort(a+1, a+n+1);
    for(int i = 1; i <= n; i++)
        pre[i] = pre[i-1] + a[i].d;
    a[0].x = -inf; a[n+1].x = inf;
}
db cal(double x, double y, int i, int j){ //计算从x走到y,下标为i~j的点已经维修过,未维修的点产生的费用 
    db caled = 0.0, t = fabs(x - y) / v;
    if(i >= 0 && j >= 0) caled = pre[j] - pre[i-1];
    return (pre[n] - caled) * t;
}
db dp(int i, int j, int k){
    if(i == 1 && j == n) return 0;
    db& ans = f[i][j][k];
    if(vis[i][j][k] == kase) return ans;
    vis[i][j][k] = kase;

    ans = inf;
    db now = (k == 0 ? a[i].x : a[j].x);
    if(i > 1) ans = min(ans, dp(i-1, j, 0) + cal(now, a[i-1].x, i, j));
    if(j < n) ans = min(ans, dp(i, j+1, 1) + cal(now, a[j+1].x, i, j));
    return ans;
}

void work(){
    while(scanf("%d%lf%lf", &n, &v, &x)  == 3 && n){
        init();
        ++kase;
        for(int i = 1; i <= n+1; i++)
            if(a[i-1].x < x && a[i].x >= x){
                if(i > 1) ans = min(ans, dp(i-1, i-1, 0) + cal(x, a[i-1].x, -1, -1));
                if(i <= n) ans = min(ans, dp(i, i, 0) + cal(x, a[i].x, -1, -1));
                break;
            }
        printf("%.0lf\n", floor(ans + s));
    }
}

int main(){
    init();
    work();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值