ZOJ3469 Food Delivery (经典区间dp)

本题和某一年的oi题非常相似,都是经典套路

我们知道我们在送完食物后既可以向前送也可以回头送,这就体现了区间dp的思想

为什么我们这次的区间dp不用枚举第三维k来枚举从哪里送过来呢?

因为送货员不是傻子,他如果送到你这了,那么在你们两之间的可以都顺路送了,所以我们只需要枚举两个位置就行

这题的输入不一定递增,所以建议输入完后排序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
ll    f[1100][1100][2];
ll s[N];
struct node{
    int x;
    int v;
    bool operator <(const node & t){
        return x<t.x;
    }
}num[N];
int main(){
    int i;
    int n;
    int v;
    int x;
    while(cin>>n>>v>>x){
        int cnt=0;
        for(i=1;i<=n;i++){
            cin>>num[i].x>>num[i].v;    
        }
        n++;
        num[n].x=x;
        num[n].v=0;
        sort(num+1,num+1+n);
        int i;
        int pos;
        for(i=1;i<=n;i++)
        s[i]=s[i-1]+num[i].v;
        for(i=1;i<=n;i++){
            if(num[i].x==x){
                pos=i;
                break;
            }
        }
        memset(f,0x3f,sizeof f);
        int len,j,k;
        int l,r;
        f[pos][pos][1]=f[pos][pos][0]=0;
        for(len=2;len<=n;len++){
            for(l=1;l+len-1<=n;l++){
            r=l+len-1;
            f[l][r][1]=min(f[l+1][r][0]+(s[l]+s[n]-s[r])*(num[r].x-num[l].x),f[l+1][r][1]+(s[l]+s[n]-s[r])*(num[l+1].x-num[l].x));
            f[l][r][0]=min(f[l][r-1][0]+(s[l-1]+s[n]-s[r-1])*(num[r].x-num[r-1].x),f[l][r-1][1]+(num[r].x-num[l].x)*(s[l-1]+s[n]-s[r-1]));
            }
        }
        cout<<min(f[1][n][1],f[1][n][0])*v<<endl;
    }
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12329984.html