区间DP ZOJ3469

  1. 参考blog:

https://blog.csdn.net/sdjzping/article/details/19070869

  1. 题目:大意抄:

有一家快餐店送外卖,现在同时有n个家庭打进电话订购,送货员得以V-1的速度一家一家的运送,但是每一个家庭都有一个不开心的值,每分钟都会增加一倍,值达到一定程度,该家庭将不会再订购

外卖了,现在为了以后有更多的家庭订购,要将外卖送到的情况下使得所有用户的不开心值总和达到最小

很明显,每多走一分钟,没送到的家庭的不开心值都会加倍,

假设是这样的顺序123X456,从X出发先往左右中间靠近的送,再往两边送省时间

dp[i][j][0]表示从i到j用户送到最小不开心值,此时送货员停留在左边即i位置

dp[i][j][1]表示从i到j用户送到最小不开心值,此时送货员停留在右边即j位置

状态有四种,

        dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(a[i+1].x-a[i].x)*(delay+a[i].v));
        dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(a[j].x-a[i].x)*(delay+a[i].v));
        dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(a[j].x-a[i].x)*(delay+a[j].v));
        dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(a[j].x-a[j-1].x)*(delay+a[j].v));
  1. 本人思路:

    一开始其实和上面的状态转移方程大致一样,就是漏了个delay,于是我以为每个dp除了记录总b还得记录时间,但是这并不需要。因为如果我们已经把还没到的家庭的产生的不开心值算进去,那么后面由此得到的母区间的状态就不需要时间去维护了。这是关键。
    小错误:
    一开始的dp初始化:
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190731233815646.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc2ODc3NA==,size_16,color_FFFFFF,t_70)
    这个是有问题,因为没有把所有的dp都初始化了,那些还是会用到的比如dp[i][i]这种就完全初始化到。debug很久才发现这个问题。。
    
  2. 代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e3+4;
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const double pi=acos(-1.0);
struct node{
    int b;int x;
    node(int _x,int _b):x(_x),b(_b)
    {
    }
    node(){}
    bool operator<(const node & tmp)const{
         return x<tmp.x;
    }
    bool operator == (const node & tmp)const{
    return x==tmp.x;
    }

}p[maxn];
LL sum[maxn];
LL dp[maxn][maxn][2];
int N,V,X;int x,b;
int main()
{
    while(cin>>N>>V>>X)
    {
        memset(sum,0,sizeof(sum));

        for(int j=1;j<=N;j++)
        {
               cin>>x>>b;
                p[j]=node(x,b);
        }
        p[N+1].x=X;
        p[N+1].b=0;
        sort(p+1,p+N+2);
        int pos;
        pos=find(p+1,p+N+2,node(X,0))-p;

        for(int j=1;j<=N+1;j++)
            sum[j]=sum[j-1]+p[j].b;

        for(int i=1; i<=N+1; i++)
        {
            for(int j=1; j<=N+1; j++)
                dp[i][j][0]=dp[i][j][1]=INF;
        }
        dp[pos][pos][0]=dp[pos][pos][1]=0;
        for(int i=pos;i>=1;i--)
        {
            for(int j=pos;j<=N+1;j++)
            {
                LL delay=sum[i-1]+sum[N+1]-sum[j];
                if(i==j)
                    continue;
                dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(p[i+1].x-p[i].x)*(delay+p[i].b));
                dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(p[j].x-p[i].x)*(delay+p[i].b));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(p[j].x-p[j-1].x)*(delay+p[j].b));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(p[j].x-p[i].x)*(delay+p[j].b));
            }
        }
        cout<<min(dp[1][N+1][0],dp[1][N+1][1])*V<<endl;//注意这里先把V当作1,前面计算好操作,最后记得加V。
    }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值