100道动态规划——18 UVA 1336 Fixing the Great Wall 指标函数的分解,刷表法

这道题目的在处理状态转移上面和我以前写过的一道题有点相似http://blog.csdn.net/good_night_sion_/article/details/52918040,这两个的思想是类似的,把一整个代价拆成一次次,然后累加

这道题目我用的是刷表法,为了计算代价的时候方便,采用了一个前缀和数组来储存delta。

状态的定义在之前也看到过,定义状态[i][j][k],表示i~j的区间走完现在处在k处(k==0在i,k==1在j)的最小代价。

区间每一次是向外延拓一个修缮点的,不可能去修理离区间有2个修缮点的地方,然后再返回来修。因为修理是不计时间的,与其先跑过去再回来,还不如去的时候就直接修掉,因此状态转移方程就很好的看出来了,在每一个状态下考虑向左走和向右走。

为了处理方便,我把起始点也看成了一个修缮点,不过这个修缮点的cost和delta都是0。

为什么在scanf后面不写==3就TLE呀!害得我找了好久!绝对数据最后有问题!

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cfloat>

using namespace std;

struct Node{
    int dis,delta,cost;
    Node(int a=0,int b=0,int c=0):dis(a),cost(b),delta(c){}
    bool operator<(const Node& a)const{return dis<a.dis;}
}arr[1010];
int n,v,x,prefix[1010];
double dp[1010][1010][2];

int main(){
    int te;
    while(scanf("%d%d%d",&n,&v,&x)==3&&n){
        for(int i=0;i<n;++i)
            scanf("%d%d%d",&arr[i].dis,&arr[i].cost,&arr[i].delta);
        arr[n]=Node(x);
        sort(arr,arr+n+1);
        prefix[0]=arr[0].delta;
        for(int i=1;i<=n;++i)
            prefix[i]=prefix[i-1]+arr[i].delta;

        for(int i=0;i<=n;++i)
        for(int j=0;j<=n;++j)
            dp[i][j][0]=dp[i][j][1]=DBL_MAX;

        for(int i=0;i<=n;++i)
        if(arr[i].dis==x)
            te=i,i=n;

        dp[te][te][0]=dp[te][te][1]=0;

        for(int length=1;length<=n;++length)
        for(int i=0,j=i+length-1;j<=n;++i,++j){
            if(dp[i][j][0]!=DBL_MAX){
                if(i)
                    dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][0]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[i].dis-arr[i-1].dis)*1.0/v+arr[i-1].cost);
                if(j<n)
                    dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][0]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[j+1].dis-arr[i].dis)*1.0/v+arr[j+1].cost);
            }
            if(dp[i][j][1]!=DBL_MAX){
                if(i)
                    dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][1]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[j].dis-arr[i-1].dis)*1.0/v+arr[i-1].cost);
                if(j<n)
                    dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][1]+(prefix[n]-prefix[j]+prefix[i-1])*(arr[j+1].dis-arr[j].dis)*1.0/v+arr[j+1].cost);
            }
        }

        printf("%.lf\n",floor(min(dp[0][n][0],dp[0][n][1])));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值