再看区间dp

来源:互联网 发布:淘宝上微信解封 编辑:程序博客网 时间:2024/06/10 01:40

区间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 longusing 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不要被大多数情况给迷惑了,还是要具体问题具体分析的