再看区间dp

区间dp就是我知道区间长度为len-1的所有状态,然后我可以通过小于len的的状态转移到区间长度为len的状态

一般是在外层循环遍历len,内层循环遍历起点来做的

但是这次做了一个很特别的题目

题目描述:

  在x轴上有n个客人叫外卖,每个顾客因为追的番更新进度不同,所以在等外买的时间里每秒增加的愤怒值不同。给出客人和餐厅的位置,以及客人每分钟增加的愤怒值,还有快递小哥的行走一公里需要的时间。问送完外卖后n个客人的最小愤怒值?

解题思路:

  区间DP,大一的时候做省赛练习的时候见过这种类型的题目,但是今天遇到由于年代久远,还是GG······。 
  把餐厅所在的点加进去,然后按照在x轴上的位置排序。从餐厅所在位置向左右开始DP,dp[x][y][z] 代表 处理完区间[y, z]停留在x方向的最小花费,这个题目要预处理未加进去点的花费。然后选取最优。


zoj 3469

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define maxn 1100
#define ll long long
using namespace std;

struct Data
{
    ll x,p;
};

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

Data a[maxn];

ll dp[maxn][maxn][3];
ll sum[maxn];

int main()
{
    ll n,V,X;
    while(~scanf("%lld %lld %lld",&n,&V,&X))
    {
        for (ll k=1;k<=n;k++)
            scanf("%lld %lld",&a[k].x,&a[k].p);
        a[n+1].x=X;a[n+1].p=0;
        n++;
        sort(a+1,a+n+1,cmp);

        sum[0]=0;
        for (ll k=1;k<=n;k++)
            sum[k]=sum[k-1]+a[k].p;

        for (ll i=0;i<=n;i++)
            for (ll j=0;j<=n;j++)
                dp[i][j][0]=dp[i][j][1]=0x3f3f3f3f;


        ll res;
        for (ll k=1;k<=n;k++)
            if (a[k].x==X)
                {dp[k][k][0]=dp[k][k][1]=0;res=k;break;}

        for (ll i=res;i>=1;i--)
            for (ll j=res;j<=n;j++)
        {
            if (i==j)
                continue;

            if (i == j) continue;
                dp[i][j][0] = min (dp[i][j][0], dp[i+1][j][0]+(sum[n]-sum[j]+sum[i])*(a[i+1].x - a[i].x));//这个其实特别奇妙,就是 
													  //我其实算值的增量的时候算的是
													  //区间外的增量

         	dp[i][j][0] = min (dp[i][j][0], dp[i+1][j][1]+(sum[n]-sum[j]+sum[i])*(a[j].x - a[i].x));
		dp[i][j][1] = min (dp[i][j][1], dp[i][j-1][1]+(sum[n]-sum[j-1]+sum[i-1])*(a[j].x - a[j-1].x));
		dp[i][j][1] = min (dp[i][j][1], dp[i][j-1][0]+(sum[n]-sum[j-1]+sum[i-1])*(a[j].x - a[i].x));
	}
	printf("%lld\n",min(dp[1][n][1],dp[1][n][0])*V);
    }
    return 0;
}   
//所以区间dp不要被大多数情况给迷惑了,还是要具体问题具体分析的



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值