区间DP:Largest Sum of Averages

版权声明:, https://blog.csdn.net/u011760195/article/details/86182740

区间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))。

猜你喜欢

转载自blog.csdn.net/u011760195/article/details/86182740