zoj 3469 Food Delivery(区间DP&&贪心&&分状态讨论)

 有一家快餐店送外卖,现在同时有n个家庭打进电话订购,送货员得以V-1的速度一家一家的运送,但是每一个家庭都有一个不开心的值,每分钟都会增加一倍,值达到一定程度,该家庭将不会再订购外卖了,现在为了以后有更多的家庭订购,要将外卖送到的情况下使得所有用户的不开心值总和达到最小

先将各个点按坐标排序,餐厅也算一个点;从小到大排序;

状态转移方程:

从餐厅向两边遍历:i为左,j为右,dp[i][j][0]代表从i->j的区间,且最终停在左边;

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

........i...i+1...reataurant......j-1...j

(delay+p[i].d)代表总的愤怒值,(p[i+1].x-p[i].x))代表两点间距离即i+1->i;

下面同上;
            dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(delay+p[i].d)*(p[j].x-p[i].x));
 //愤怒总值乘上两点距离;在主函数中乘上V即可;因为愤怒值*t为所求,但是s*V=t;题目中的V为速度的倒数
            dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(delay+p[j].d)*(p[j].x-p[i].x));
            dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(delay+p[j].d)*(p[j].x-p[j-1].x));

 

/*********************
功能:x轴上有n个位置,每个位置有一个随时间增长的参数,要求从某个点开始,经过所有的点,并且使所有点的参数之和最小
参数:每个点的位置以及这个点的参数
返回值:最小的参数和
参数和不超过INF,最多maxn个点
*********************/

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define maxn 1010
#define INF 1100000000
using namespace std;

struct P
{
    int x;
    int d;
};

P p[maxn];
int dp[maxn][maxn][2];
int sum[maxn];

bool cmp(P a,P b)
{
    return a.x<b.x;
}

int get_delay(int i,int j)
{
    if(i>j)
        return 0;
    else
        return sum[j]-sum[i-1];//返回两位置之间愤怒总值
}

int solve(int n,int X)
{
    int res,delay;
    int i,j;
    for(i=0;i<n;i++)
        if(p[i].x==X)
        {
            res=i;
            break;//找到餐厅位置,从餐厅向左右两边遍历;
        }
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            dp[i][j][0]=dp[i][j][1]=INF;//;初始化都为很大
    dp[res][res][0]=dp[res][res][1]=0;//餐厅默认为0
    for(i=res;i>=0;i--)
    {
        for(j=res;j<n;j++)
        {//从餐厅向左右两边遍历;
            if(i==j)
                continue;
            delay=get_delay(0,i-1)+get_delay(j+1,n-1);//计算两点以外的愤怒总值
            dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(delay+p[i].d)*(p[i+1].x-p[i].x));
            dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(delay+p[i].d)*(p[j].x-p[i].x));
 //愤怒总值乘上两点距离;在主函数中乘上V即可;因为愤怒值*t为所求,但是s*V=t;题目中的V为速度的倒数
            dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(delay+p[j].d)*(p[j].x-p[i].x));
            dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(delay+p[j].d)*(p[j].x-p[j-1].x));
        }
    }
    return min(dp[0][n-1][0],dp[0][n-1][1]);
}//遍历到两边;


int main()
{
    int n,v,x;
    int i;
    while(~scanf("%d%d%d",&n,&v,&x))
    {
        for(i=0;i<n;i++)
            scanf("%d%d",&p[i].x,&p[i].d);//输入每个点的坐标,及愤怒值
        p[n].x=x;//默认第n个点为餐厅坐标
        p[n].d=0;//愤怒值为0
        n++;
        sort(p,p+n,cmp);//按坐标排序;
        memset(sum,0,sizeof(sum));
        for(sum[0]=p[0].d,i=1;i<n;i++)
            sum[i]=sum[i-1]+p[i].d;//计算坐标之间愤怒值;;;;;;
        printf("%d\n",solve(n,x)*v);//最后乘上v
    }
    return 0;
}
/**********************
输入:
5 1 0
1 1
2 2
3 3
4 4
5 5
输出
55
**********************/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值