区间DP:Largest Sum of Averages

区间DP:Largest Sum of Averages

区间DP

leetcode 上面的一道题

We partition a row of numbers A into at most K adjacent (non-empty) groups, then our score is the sum of the average of each group. What is the largest score we can achieve?
Note that our partition must use every number in A, and that scores are not necessarily integers.

Example:
Input:
A = [9,1,2,3,9]
K = 3
Output: 20
Explanation:
The best choice is to partition A into [9], [1, 2, 3], [9]. The answer is 9 + (1 + 2 + 3) / 3 + 9 = 20.
We could have also partitioned A into [9, 1], [2], [3, 9], for example.
That partition would lead to a score of 5 + 2 + 6 = 13, which is worse.

具体意思:将一个数组划分为k组,使得每组平均值总和最大。
不难列出状态转移方程
在这里插入图片描述

递归版本代码(我的代码)

class Solution {
public:
	double gmax(int* arr,int size ,int K) {
		if (size <=0) return 0.;
		if (K == 1) {
			double aver = 0.;
			for (int a = 0;a < size;++a) {
				aver += *arr++;
			}
			return aver / size;
		}
		int end = size - K + 1, t;
		double *m = new double[size]();
		double aver = 0.;
		for (auto k = 1;k <= end; ++k) {
			t = size - k;
			aver += arr[k-1];
			m[k - 1] = aver/k + gmax(arr+k, t,K - 1);
		}
		double r = 0.;
		for (int i = 0;i < size;++i) {
			r = max(m[i], r);
		}
		delete[]m;
		return r;

	}
	
	double largestSumOfAverages(vector<int>& A, int K) {
	
		return gmax(&A[0],A.size(),K);

	}
};

效率很低,下面是例解

class Solution {
    public double largestSumOfAverages(int[] A, int K) {
        int N = A.length;
        double[] P = new double[N+1];
        for (int i = 0; i < N; ++i)
            P[i+1] = P[i] + A[i];

        double[] dp = new double[N];
        for (int i = 0; i < N; ++i)
            dp[i] = (P[N] - P[i]) / (N - i);

        for (int k = 0; k < K-1; ++k)
            for (int i = 0; i < N; ++i)
                for (int j = i+1; j < N; ++j)
                    dp[i] = Math.max(dp[i], (P[j]-P[i]) / (j-i) + dp[j]);

        return dp[0];
    }
}

If the first group we partition A[i:] into ends before j, then our candidate partition has score average(i, j) + dp(j, k-1)), where average(i, j) = (A[i] + A[i+1] + … + A[j-1]) / (j - i) (floating point division). We take the highest score of these, keeping in mind we don’t necessarily need to partition - dp(i, k) can also be just average(i, N).
In total, our recursion in the general case is dp(i, k) = max(average(i, N), max_{j > i}(average(i, j) + dp(j, k-1))).
We can calculate average a little bit faster by remembering prefix sums. If P[x+1] = A[0] + A[1] + … + A[x], then average(i, j) = (P[j] - P[i]) / (j - i).
Our implementation showcases a “bottom-up” style of dp. Here at loop number k in our outer-most loop, dp[i] represents dp(i, k) from the discussion above, and we are calculating the next layer dp(i, k+1). The end of our second loop for i = 0…N-1 represents finishing the calculation of the correct value for dp(i, t), and the inner-most loop performs the calculation max_{j > i}(average(i, j) + dp(j, k))

译文

如果我们将数组A 从 i 到 j 分成第一部分,那么该组的最大值为 average(i,j)+dp(j,k-1)),其中 average(i,j)=(a[i]+a[i+1]+…+a[j-1])/(j-i)。取得最大值,而不需要划分 dp(i,k)
总的来说,我们在一般情况下的递归是 dp(i,k)=max(平均值(i,n),max_j >i(average(i,j)+ dp(j,k-1))。
通过记录前缀和,我们可以更快地计算平均值。如果p[x+1]=a[0]+a[1]+…+a[x],则平均值(i,j)=(p[j]-p[i])/(j-i)。
我们的实现展示了一种“自下而上”的DP风格。在我们最外层的圈数k处,dp[i]表示上面讨论的dp(i,k),我们正在计算下一层dp(i,k+1)。i=0…n-1的第二个循环的结束表示完成dp(i,t)的正确值的计算,最内部的循环执行计算max_j >i(平均值(i,j)+dp(j,k))。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值