线性DP之小烈送菜

时间:2020-07-02
本文章向大家介绍线性DP之小烈送菜,主要包括线性DP之小烈送菜使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

小烈送菜

  • 小烈一下碰碰车就被乐满地的工作人员抓住了。作为扰乱秩序的惩罚,小烈必须去乐满地里的“漓江村”饭店端盘子。

  • 服务员的工作很繁忙。他们要上菜,同时要使顾客们尽量高兴。一位服务生为 n个顾客上菜。这 n 个顾客坐成一排,小烈从一端的厨房中端出 n 盘菜(不要问我为什么小烈能一下子端住 2500 盘菜,他就是能)为 n个顾客各上一道相同的菜。显然,小烈需要走一个来回,如图:本来,小烈可以按 1,2,3...n的顺序一次给每个顾客上菜,但是,聪明的小烈通过观察发现,每个顾客都有一个开心值 H1,H2,H3…,Hn ,离厨房最近的为 H1,然后依次为 H2,H3…,Hn 。若小烈给第 j 位顾客上菜前刚刚为第 i 位顾客上菜,则第 j 位就会高兴,产生高兴指数 Wj=Hi×Hj 。这样,如果小烈按一定的方式调整上菜顺序,可以得到更高的高兴指数。现在小烈想知道用某一方法可达到的 n 位顾客高兴指数之和的最大值S 。因为顾客越高兴,给小烈的小费越多。第一位上菜的顾客不产生高兴值。

Input

第一行一个整数 n,顾客的数目。
第二行 n个数,第 i 个数表示第 i位顾客的开心值。各个数字用空格隔开。

Output

一个数 s,为高兴指数的最大值。

样例

Sample Input

3
7 1 9

Sample Output

72

Hint

样例解释:

从左往右上 1的菜,再上 9 的菜,高兴值是 0∗1+1∗9,从右往左走回来的时候上 7 的菜,高兴值是 7∗9,总的高兴值就是 7。
对于30%的数据 n≤9,n∈N+;
对于70%的数据 n≤1500,n∈N+;
对于100%的数据 n≤2500,n∈N+;
所有数字小于(含结果)2147483648;

思路

这道题有点像(方格取树)[https://www.cnblogs.com/soda-ma/p/13226890.html] ,这就启发我们将题目所描述的情形变成两个小烈同时从左边往右边走,容易看出,这样转化是等价的。同时,我们需要注意的是每个位置都必须送到,而且只能有两个小烈里面的其中一个送到。这样考虑之后,状态之间的转移关系就很显然了。f[i][j] 表示小烈 a 和小烈 b 分别走到了 i,j 位置,同时记 m=max(x1,x2),对于小于 m 的每一个位置都已经被送到。那么,在 f[i][j] 这一状态下,需要决定第 m+1 个人由谁来送菜。显然这是一个多阶段决策问题,m 就是阶段的标识。可以用动态规划求解。同时,可以发现,在第 m 个阶段通过决策转移到 m+1 个阶段是,每一个决定(小烈a来送还是小烈 b来送)都对应一个状态为:f[m+1][j] 和 f[i][m+1] 。因为在送的过程中,每个位置都需要送到,而且两个小烈都是一样的,所以,f[i][j]==f[j][i] 。这样,我们让小烈 a 始终在前面,小烈 b 在后面,即,f[i][j] 保证 i>j 。

  • f[i+1][j]=max(f[i+1][j],f[i][j]+a[i]∗a[i+1]) ,i+1 由 i 转移过来
  • f[i+1][i]=max(f[i+1][i],f[i][j]+a[j]∗a[i+1]),i+1 由 j 转移过来

附上代码



#include<bits/stdc++.h>
using namespace std;
const int maxn=2500+5;
int a[maxn],f[maxn][maxn];
int main(){
	int n,ans=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++){
		for(int j=0;j<i;j++){
			f[i+1][j]=max(f[i+1][j],f[i][j]+a[i]*a[i+1]);
			f[i+1][i]=max(f[i+1][i],f[i][j]+a[j]*a[i+1]);
		}
	}
	for(int i=0;i<n;i++)
		ans=max(ans,f[n][i]+a[n]*a[i]);
	printf("%d\n",ans);
	
}

原文地址:https://www.cnblogs.com/soda-ma/p/13227016.html