本题和某一年的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; } }
原文地址:https://www.cnblogs.com/ctyakwf/p/12329984.html
时间: 2024-10-11 15:35:39