给定一个由N 个数字组成的数组arr[] 。我们可以将两个相邻的数字合并为一个,合并两个数字的成本等于两个值的总和。任务是找到合并所有数字的总最小成本。
例子:
Input: arr[] = { 6, 4, 4, 6 }
Output: 40
Explanation:
Following is the optimal way of merging numbers to get the total minimum cost of merging of numbers:
1. Merge (6, 4), then array becomes, arr[] = {10, 4, 6} and cost = 10
2. Merge (4, 6), then array becomes, arr[] = {10, 10} and cost = 10
3. Merge (10, 10), then array becomes, arr[] = {20} and cost = 20
Hence the total cost is 10 + 10 + 20 = 40.
Input: arr[] = { 3, 2, 4, 1 }
Output: 20
Explanation:
Following is the optimal way of merging numbers to get the total minimum cost of merging of numbers:
1. Merge (3, 2), then array becomes, arr[] = {5, 4, 1} and cost = 5
2. Merge (4, 1), then array becomes, arr[] = {5, 5} and cost = 5
3. Merge (5, 5), then array becomes, arr[] = {10} and cost = 10
Hence the total cost is 5 + 5 + 10 = 20.
方法:该问题可以使用动态规划解决。以下是步骤:
- 这个想法是将2 个连续的数字合并到每个可能的索引i 中,然后递归求解索引i 的左右部分。
- 将上述步骤中合并两个数字的结果相加并存储它们中的最小值。
- 由于有许多重复的子问题,因此我们使用记忆化将值存储在NxN矩阵中。
- 上述问题陈述的递推关系如下:
dp[i][j] = min(dp[i][j], (sum[i][j] + dp[i][k] + dp[k + 1][j])), for every (i ≤ k lt; j)
5. 现在dp[1][N]将给出合并所有数字的最小总成本。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to find the total minimum
// cost of merging two consecutive numbers
int mergeTwoNumbers(vector& numbers)
{
int len, i, j, k;
// Find the size of numbers[]
int n = numbers.size();
// If array is empty, return 0
if (numbers.size() == 0) {
return 0;
}
// To store the prefix Sum of
// numbers array numbers[]
vector prefixSum(n + 1, 0);
// Traverse numbers[] to find the
// prefix sum
for (int i = 1; i <= n; i++) {
prefixSum[i] = prefixSum[i - 1]
+ numbers[i - 1];
}
// dp table to memoised the value
vector > dp(
n + 1,
vector(n + 1));
// For single numbers cost is zero
for (int i = 1; i <= n; i++) {
dp[i][i] = 0;
}
// Iterate for length >= 1
for (len = 2; len <= n; len++) {
for (i = 1; i <= n - len + 1; i++) {
j = i + len - 1;
// Find sum in range [i..j]
int sum = prefixSum[j]
- prefixSum[i - 1];
// Initialise dp[i][j] to INT_MAX
dp[i][j] = INT_MAX;
// Iterate for all possible
// K to find the minimum cost
for (k = i; k < j; k++) {
// Update the minimum sum
dp[i][j]
= min(dp[i][j],
dp[i][k]
+ dp[k + 1][j]
+ sum);
}
}
}
// Return the final minimum cost
return dp[1][n];
}
// Driver Code
int main()
{
// Given set of numbers
vector arr1 = { 6, 4, 4, 6 };
// Function Call
cout << mergeTwoNumbers(arr1)
<< endl;
return 0;
}
Java
// Java program for the above approach
import java.util.*;
class GFG{
// Function to find the total minimum
// cost of merging two consecutive numbers
static int mergeTwoNumbers(int []numbers)
{
int len, i, j, k;
// Find the size of numbers[]
int n = numbers.length;
// If array is empty, return 0
if (numbers.length == 0)
{
return 0;
}
// To store the prefix Sum of
// numbers array numbers[]
int []prefixSum = new int[n + 1];
// Traverse numbers[] to find the
// prefix sum
for (i = 1; i <= n; i++)
{
prefixSum[i] = prefixSum[i - 1] +
numbers[i - 1];
}
// dp table to memoised the value
int [][]dp = new int[n + 1][n + 1];
// Iterate for length >= 1
for (len = 2; len <= n; len++)
{
for (i = 1; i <= n - len + 1; i++)
{
j = i + len - 1;
// Find sum in range [i..j]
int sum = prefixSum[j] -
prefixSum[i - 1];
// Initialise dp[i][j] to Integer.MAX_VALUE
dp[i][j] = Integer.MAX_VALUE;
// Iterate for all possible
// K to find the minimum cost
for (k = i; k < j; k++)
{
// Update the minimum sum
dp[i][j] = Math.min(dp[i][j],
dp[i][k] +
dp[k + 1][j] +
sum);
}
}
}
// Return the final minimum cost
return dp[1][n];
}
// Driver Code
public static void main(String[] args)
{
// Given set of numbers
int []arr1 = { 6, 4, 4, 6 };
// Function Call
System.out.print(mergeTwoNumbers(arr1) + "\n");
}
}
// This code is contributed by sapnasingh4991
Python3
# Python3 program for the above approach
import sys
# Function to find the total minimum
# cost of merging two consecutive numbers
def mergeTwoNumbers(numbers):
# Find the size of numbers[]
n = len(numbers)
# If array is empty, return 0
if (len(numbers) == 0):
return 0
# To store the prefix Sum of
# numbers array numbers[]
prefixSum = [0] * (n + 1)
# Traverse numbers[] to find the
# prefix sum
for i in range(1, n + 1):
prefixSum[i] = (prefixSum[i - 1] +
numbers[i - 1])
# dp table to memoised the value
dp = [[0 for i in range(n + 1)]
for j in range(n + 1)]
# For single numbers cost is zero
for i in range(1, n + 1):
dp[i][i] = 0
# Iterate for length >= 1
for p in range(2, n + 1):
for i in range(1, n - p + 2):
j = i + p - 1
# Find sum in range [i..j]
sum = prefixSum[j] - prefixSum[i - 1]
# Initialise dp[i][j] to _MAX
dp[i][j] = sys.maxsize
# Iterate for all possible
# K to find the minimum cost
for k in range(i, j):
# Update the minimum sum
dp[i][j] = min(dp[i][j],
(dp[i][k] +
dp[k + 1][j] + sum))
# Return the final minimum cost
return dp[1][n]
# Driver Code
# Given set of numbers
arr1 = [ 6, 4, 4, 6 ]
# Function call
print(mergeTwoNumbers(arr1))
# This code is contributed by sanjoy_62
C#
// C# program for the above approach
using System;
class GFG{
// Function to find the total minimum
// cost of merging two consecutive numbers
static int mergeTwoNumbers(int []numbers)
{
int len, i, j, k;
// Find the size of numbers[]
int n = numbers.Length;
// If array is empty, return 0
if (numbers.Length == 0)
{
return 0;
}
// To store the prefix Sum of
// numbers array numbers[]
int []prefixSum = new int[n + 1];
// Traverse numbers[] to find the
// prefix sum
for (i = 1; i <= n; i++)
{
prefixSum[i] = prefixSum[i - 1] +
numbers[i - 1];
}
// dp table to memoised the value
int [,]dp = new int[n + 1, n + 1];
// Iterate for length >= 1
for (len = 2; len <= n; len++)
{
for (i = 1; i <= n - len + 1; i++)
{
j = i + len - 1;
// Find sum in range [i..j]
int sum = prefixSum[j] -
prefixSum[i - 1];
// Initialise dp[i,j] to int.MaxValue
dp[i,j] = int.MaxValue;
// Iterate for all possible
// K to find the minimum cost
for (k = i; k < j; k++)
{
// Update the minimum sum
dp[i, j] = Math.Min(dp[i, j],
dp[i, k] +
dp[k + 1, j] +
sum);
}
}
}
// Return the readonly minimum cost
return dp[1, n];
}
// Driver Code
public static void Main(String[] args)
{
// Given set of numbers
int []arr1 = { 6, 4, 4, 6 };
// Function Call
Console.Write(mergeTwoNumbers(arr1) + "\n");
}
}
// This code is contributed by sapnasingh4991
Javascript
40
时间复杂度: O(N 3 )
辅助空间复杂度: O(N 2 )