zoj3469Food Delivery[区间dp]

原题链接:

              zoj 3469 Food Delivery

题目大意:

  送餐员送餐问题。有n个人叫餐,每个人都在x轴上,并且每个人都有个XX度(和等餐时间有关,据说顾客认为xx值到一定程度他的小宇宙就要爆发).现在送餐员从x轴上的某点出发,路上奔跑速度是v^-1,要一次性把所有餐送完。叫餐的人得到餐的时间和顺序不同,xx度总和也就不同。合格的送餐员要让客户体验最好,请问最少xx度和为多少

这题的做法和poj3042相似,在做当前的选择时要把当前的选择对以后的影响计算进去,

首先用 dp[i][j][0]    表示送完i--j之间的顾客后在i位置时的最小值 ,dp[i][j][1]     表示送完i--j之间的顾客后在j位置时的最小值

 动态转移方程:


   dp[i][j][1]=min(dp[i][j-1][1]+(cost[n]-cost[j-1]+cost[i-1])*(p[j].x-p[j-1].x),dp[i][j-1][0]+(cost[n]-cost[j-1]+cost[i-1])*(p[j].x-p[i].x));
    dp[i][j][0]=min(dp[i+1][j][0]+(cost[n]-cost[j]+cost[i])*(p[i+1].x-p[i].x),dp[i+1][j][1]+(cost[n]-cost[j]+cost[i])*(p[j].x-p[i].x));

ps:由于没看清v的含义,无限受伤啊,。。。 (v不是速度额,亲)

喳喳代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1100
using namespace std;
struct node
{
    int x,b;
} p[N];
int n,v,x0,s;
int dp[N][N][2];
int cost[N];
bool cmp(node a,node b)
{
    return  a.x<b.x;
}
int solve()
{
    memset(dp,0x3f,sizeof(dp));//这个最大值不能太大,否则下面转移方程会尴尬。。。
    dp[s][s][0]=dp[s][s][1]=0;
    for(int i=s; i>0; i--)
        for(int j=s; j<=n; j++)
        {
            if(i==s&&j==s)continue; //可以暂时不用速度,最后再处理
            dp[i][j][1]=min(dp[i][j-1][1]+(cost[n]-cost[j-1]+cost[i-1])*(p[j].x-p[j-1].x),dp[i][j-1][0]+(cost[n]-cost[j-1]+cost[i-1])*(p[j].x-p[i].x));
            dp[i][j][0]=min(dp[i+1][j][0]+(cost[n]-cost[j]+cost[i])*(p[i+1].x-p[i].x),dp[i+1][j][1]+(cost[n]-cost[j]+cost[i])*(p[j].x-p[i].x));

        }
    return min(dp[1][n][0],dp[1][n][1]);
}
int main()
{
    //  freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&n,&v,&x0)!=EOF)
    {
        bool flag=false;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&p[i].x,&p[i].b);
            if(p[i].x==x0)
                flag=true;

        }
        if(!flag)
        {
            p[n+1].x=x0;
            p[n+1].b=0;
            n++;
        }
        sort(p+1,p+1+n,cmp);
        for(int i=1; i<=n; i++)
            if(p[i].x==x0)
            {
                s=i;
                break;
            }
        cost[0]=0;
        for(int i=1; i<=n; i++)
            cost[i]=cost[i-1]+p[i].b;

        printf("%d\n",v*solve());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值