UVA - 1336 Fixing the Great Wall 记忆化搜索

题目链接:UVA - 1336

最近心情炒鸡差 = = 不过么 也没什么 总会过去的 该做的还是要做的 恩。。教主说的挺对的还是要少看题解多思考。。觉得CF的题目都蛮锻炼脑子的准备刷lrj刷不动的时候做几道那个。

这是调了两天调出来的DP。。。说起来也不算很难吧,毕竟书上有解析,大意就是有个机器人在x点,移动速度v,有n个地方需要修补,给出这些点的位置,立即修补的花费c,以及每过一秒(我忘了是啥了,反正是一个单位时间),所增加的花费d,即修补某点i所需要的花费为d*abs(x[i]-x)/v+c,所以先按x对所需要修补的点进行排序,然后预处理求出前n个点的d的总和,时间每增加一个单位,总花费必然增加d[当前未修补的点集]*1,然后找到机器人所在的位置(某两点之间),从那两个位置开始求解即可。注意有可能机器人在最左边或最右边,所以应当注意遍历时数组的范围,另外后来几次错是因为循环中的小于等于写成了小于,导致只有一个点时无法求得正确结果。

#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x7f7f7f7f
using namespace std;
const int maxn = 1024;
struct Pos{
    double x,c,d;
    Pos(double a=0,double b=0,double cc=0):x(a),c(b),d(cc){}
    bool operator < (const Pos& p)const {return x<p.x;}
}p[maxn];
int n,v,x,cases=0;
double dp[maxn][maxn][2],res[maxn];
void init(){
    res[0]=0;
    for(int i=1;i<=n;i++)
        res[i]=res[i-1]+p[i].d;
}
double solve(int x,int y,int pos){
    if(x==1&&y==n) return 0;
    if(dp[x][y][pos]<INF&&dp[x][y][pos]>0) return dp[x][y][pos];
    double temp = INF;
    //cout<<"***test here***"<<endl;
    if(x>1){
        if(pos==0)//求区间的d值之和时是 1 - x-1,y - n 
            temp=min(temp,solve(x-1,y,0)+fabs(p[x].x-p[x-1].x)/v*(res[x-1]+res[n]-res[y])+p[x-1].c);
        else
            temp=min(temp,solve(x-1,y,0)+fabs(p[y].x-p[x-1].x)/v*(res[x-1]+res[n]-res[y])+p[x-1].c);
    }
    if(y<n){
        if(pos==0)
            temp=min(temp,solve(x,y+1,1)+fabs(p[x].x-p[y+1].x)/v*(res[x-1]+res[n]-res[y])+p[y+1].c);
        else
            temp=min(temp,solve(x,y+1,1)+fabs(p[y].x-p[y+1].x)/v*(res[x-1]+res[n]-res[y])+p[y+1].c);
        //cout<<"44 "<<temp<<endl;
    }
    //cout<<"***test end***"<<endl<<endl;
    return dp[x][y][pos]=temp;
}
int main() {
    while(~scanf("%d%d%d",&n,&v,&x)&&(n+v+x)){
        memset(dp,INF,sizeof(dp));
        memset(res,0,sizeof(res));
        for(int i=1;i<=n;i++)
            scanf("%lf%lf%lf",&p[i].x,&p[i].c,&p[i].d);
        sort(p+1,p+1+n);
        p[0].x=-1;
        p[n+1].x=INF;
        init();//预处理
        double ans = INF;
        for(int i=0;i<=n;i++){//注意此处范围。
            if(p[i].x<=x&&p[i+1].x>=x){
                if(i>=1)//等于
                    ans=min(ans,solve(i,i,0)+fabs(p[i].x-x)/v*res[n]+p[i].c);
                if(i<=n)
                    ans=min(ans,solve(i+1,i+1,1)+fabs(p[i+1].x-x)/v*res[n]+p[i+1].c);
                break;
            }
        }
        printf("%d\n",int(ans));
    }
    return 0;
}
希望所有像我一样在DP中挣扎的人们在不久后的某天就能将DP运用自如,加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值