zoj 3469 Food Delivery

zoj 3469 Food Delivery

题面

一维数轴上有一个外卖配送员和 \(1000\) 个客户,每个客户 \(i\) 的怒气值是他收到外卖的时间乘 \(b[i]\)\(b[i]\) 由题目给定),给出配送员速度,求一个方案使得所有客户的怒气值之和最小,输出最小怒气值之和。

题解

收到货的客户一定处在连续的一段区间内,做法是区间dp。
我们用 \(v_i\) 表示第 \(i\) 个收到外卖的客户的 \(b\) 值,\(x_i\) 表示第 \(i\) 个收到外卖的客户的坐标。 \(O\) 表示配送员初始坐标。

\(总的怒气值=\)
\(v_1*(|x_1-O|) +\)
\(v_2*(|x_1-O|+|x_2-x_1|) +\)
\(v_3*(|x_1-O|+|x_2-x_1|+|x_3-x_2|) +\)
\(... +\)
\(v_n*(|x_1-O|+|x_2-x_1|+|x_3-x_2|+...+|x_n-x_{n-1}|)\)

\(=\)
\(|x_1-O|*(v_1+v_2+...+v_n) +\)
\(|x_2-x_1|*(v_2+...+v_n) +\)
\(... +\)
\(|x_n-x_{n-1}|*(v_n)\)

\(f[i][j][0]\)表示\(i\)\(j\)这段区间的客户都已经收到外卖,此时外卖员在\(i\)处,假设这段区间有\(t\)个人。\(f[i][j][0]\)为上式中前\(t\)行。

\(f[i][j][1]\)表示外卖员在\(j\)处,其他与\(f[i][j][0]\)同理。

代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define sz(x) (int)x.size()
#define de(x) cout<< #x<<" = "<<x<<endl
#define dd(x) cout<< #x<<" = "<<x<<" "
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
//------

const int N=1010;
const ll inf=(1ll<<31);
int n,v,x;
ll f[N][N][2], sum[N];
pii a[N];

ll Sum(int l,int r) {
    ll ans=sum[n+1]-(sum[r+1]-sum[l]);
    return ans;
}

int main() {
    while(~scanf("%d%d%d",&n,&v,&x)) {
        ///init
        rep(i,0,n+1) rep(j,0,n+1) rep(k,0,2) f[i][j][k]=inf;
        ///read
        rep(i,1,n+1) {
            int x,y;scanf("%d%d",&x,&y);
            a[i]=mp(x,y);
        }
        ///solve
        a[0]=mp(x,-1);
        sort(a,a+n+1);
        rep(i,0,n+1) sum[i+1]=sum[i]+max(a[i].se, 0);
        rep(i,0,n+1) if(a[i].se==-1) f[i][i][0]=f[i][i][1]=0;
        rep(len,1,n+1) {
            for(int i=0;i+len<=n;++i) {
                int j=i+len;
                ll t0=1ll*(a[i+1].fi-a[i].fi)*Sum(i+1, j);
                ll t1=1ll*(a[j].fi-a[i].fi)*Sum(i+1, j);
                f[i][j][0]=min(f[i+1][j][0]+t0,f[i+1][j][1]+t1);
                ll t2=1ll*(a[j].fi-a[i].fi)*Sum(i, j-1);
                ll t3=1ll*(a[j].fi-a[j-1].fi)*Sum(i, j-1);
                f[i][j][1]=min(f[i][j-1][0]+t2,f[i][j-1][1]+t3);
            }
        }
        printf("%lld\n",min(f[0][n][0], f[0][n][1])*v);
    }
    return 0;
}

转载于:https://www.cnblogs.com/wuyuanyuan/p/8278886.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值