区间dp(三维)——数轴餐馆送餐

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41661919/article/details/82354335

 题意:

给定餐馆以及顾客位置,从餐馆出发给顾客送餐,并最终回到餐馆,每个顾客有一个权值,每等一分钟,不满意值加对应权值,问怎样送餐能使总的不满意度最小。

分析:

区间dp,怎么的出来的暂且不考虑。 

     考虑的餐馆的相对位置,其可能处于顾客之间,也可能处于所有顾客的某一边。对于后者,无疑按照1->2->3->4......的顺序送即可,而对于前者,可以送一段左边的顾客,在反过来送一段右边的顾客,也可以先右边,后左边,还能左边完全送完后再送右边,或者右边完全送完后送左边。

      然后,,,对于区间dp,我们先宏观考虑,想要送完1~n个顾客(最后一个人一定是1或者n),那第n-1次送的顾客是谁,显然,如果最后一个人为n的话,第n-1个人可能是1,也可能是n-1,最后一个人为1,第n-1个人可能为2或者n,所以,,,综合考虑

我们要在(二位区间的基础上加一维表示该区间最后一个被送餐的人),于是也就有状态转移方程,

dp[i][j][0]=min(dp[i]][j][0],dp[i+1][j][0]+(a[i+1].x-a[i].x)*(sum[n]-sum[j]+sum[i]));

(其他的三个方程同理可得。。。略,,,)

这里所加的权值是指我们从第i+1个人向第i个人走时其他还没得到饭的人(包括i)所产生的生气值,刚开始错因在于将dp[i][j]..描述成这段区间内的人所产生的生气值,这种描述不是不对,而是不好处理,因为这样的话,例如从i+1到i时产生的生气值,此时均为i的,但除了考虑i+1到i的这段距离外,还要考虑i+1~j之间行走的距离等等距离,而这些距离的计算用过推演发现是不好描述的(故,这样不好)。而如果将状态描述为区间外其他人产生的生气值,那在转移时就比较好实现了,(如代码),也不必考虑在i+1~j之间行走时i所产生的生气值(因为在较小区间中已经逐步将i的生气值累加到总权值中了),,,,感觉没说清楚(自己好好再想想),此时,当区间扩大到1~n时便可以得到总的生气值,然后从最后一个人为1或者n的状态中中取 小者即可。

  最后,长度为1的处理就不说了,长度为2,长度为3可以手推一下验证过程,,,还有可以发现顾客均在餐厅同一边时也是可以由上述规律实现的,只不过多了许多无用的状态(这些多余的都比对应区间的最优结果要大,所以对ans无影响),,,

AC代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include<algorithm>
#include <set>
#include <queue>
#include <stack>
#include<vector>
#include<map>
#include<ctime>
#define ll long long
#define INF 0x7fffffff
using namespace std;
ll dp[1100][1100][2];
struct point
{
    ll x,v;
}a[1200];
bool cmp(point a,point b)
{
    return a.x<b.x;
}
ll sum[1200];
int main()
{
    ll n,v,X;
    while(cin>>n>>v>>X)
    {
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
        for(ll i=1;i<=n;++i)cin>>a[i].x>>a[i].v;
        sort(a+1,a+1+n,cmp);
        for(ll i=1;i<=n;++i)sum[i]=sum[i-1]+a[i].v;
        memset(dp,0,sizeof(dp));
        for(ll i=1;i<=n;++i)dp[i][i][0]=dp[i][i][1]=abs(a[i].x-X)*sum[n];
        for(ll len=2;len<=n;++len)
        {
            for(ll i=1;i<=n&&i+len-1<=n;++i)
            {
                ll j=i+len-1;
                dp[i][j][0]=dp[i][j][1]=INF;

                dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(a[i+1].x-a[i].x)*(sum[n]-sum[j]+sum[i]));//关键******
                dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(a[j].x-a[i].x)*(sum[n]-sum[j]+sum[i]));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(a[j].x-a[i].x)*(sum[n]-sum[j-1]+sum[i-1]));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(a[j].x-a[j-1].x)*(sum[n]-sum[j-1]+sum[i-1]));

            }
        }
        cout<<v*min(dp[1][n][0],dp[1][n][1])<<endl;

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41661919/article/details/82354335