有n条不同长度的绳索,我们需要将这些绳索连接成一条绳索。连接两条绳索的成本等于其长度之和。我们需要以最小的成本连接绳索。
例如,如果给我们4条长度分别为4、3、2和6的绳索,我们可以通过以下方式进行连接。
1)首先,连接长度为2和3的绳索。现在,我们有了三根长度为4、6和5的绳索。
2)现在连接长度为4和5的绳索。现在有两条长度为6和9的绳索。
3)最后连接两条绳索,所有绳索均已连接。
连接所有绳索的总成本为5 + 9 + 15 =29。这是连接绳索的最佳成本。连接绳索的其他方式将始终具有相同或更多的成本。例如,如果我们首先连接4和6(我们得到三个字符串,分别为3、2和10),然后连接10和3(我们得到两个字符串,分别为13和2)。最后,我们将13和2连接起来。这种方式的总成本为10 + 13 + 15 = 38。
我们强烈建议您单击此处并进行实践,然后再继续解决方案。
解决方案:
如果我们仔细观察上述问题,我们会注意到,首先被挑选的绳索的长度被计入总成本中不止一次。因此,我们的想法是先连接最小的两根绳索,然后再重复剩余的绳索。这种方法类似于霍夫曼编码。我们将最小的绳索放在树上,这样它们可以重复多次而不是更长的绳索。
因此,它形成了像树一样的结构:
该和包含每个值的深度之和。对于数组(2、3、4、6),总和等于2 * 3 + 3 * 3 + 4 * 2 + 6 * 1 = 29(根据该图)。
算法:
- 创建一个最小堆并将所有长度插入到最小堆中。
- 当min-heap中的元素数不为1时,请执行以下操作。
- 从最小堆中提取最小值和第二最小值
- 将以上两个提取的值相加,然后将相加后的值插入到最小堆中。
- 维持总成本的变量,并按提取值的总和不断增加变量。
- 返回此总成本的值。
以下是上述算法的实现。
C++
// C++ program for connecting
// n ropes with minimum cost
#include
using namespace std;
// A Min Heap: Collection of min heap nodes
struct MinHeap {
unsigned size; // Current size of min heap
unsigned capacity; // capacity of min heap
int* harr; // Attay of minheap nodes
};
// A utility function to create
// a min-heap of a given capacity
struct MinHeap* createMinHeap(unsigned capacity)
{
struct MinHeap* minHeap = new MinHeap;
minHeap->size = 0; // current size is 0
minHeap->capacity = capacity;
minHeap->harr = new int[capacity];
return minHeap;
}
// A utility function to swap two min heap nodes
void swapMinHeapNode(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// The standard minHeapify function.
void minHeapify(struct MinHeap* minHeap, int idx)
{
int smallest = idx;
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < minHeap->size
&& minHeap->harr[left] < minHeap->harr[smallest])
smallest = left;
if (right < minHeap->size
&& minHeap->harr[right] < minHeap->harr[smallest])
smallest = right;
if (smallest != idx) {
swapMinHeapNode(&minHeap->harr[smallest], &minHeap->harr[idx]);
minHeapify(minHeap, smallest);
}
}
// A utility function to check
// if size of heap is 1 or not
int isSizeOne(struct MinHeap* minHeap)
{
return (minHeap->size == 1);
}
// A standard function to extract
// minimum value node from heap
int extractMin(struct MinHeap* minHeap)
{
int temp = minHeap->harr[0];
minHeap->harr[0] = minHeap->harr[minHeap->size - 1];
--minHeap->size;
minHeapify(minHeap, 0);
return temp;
}
// A utility function to insert
// a new node to Min Heap
void insertMinHeap(struct MinHeap* minHeap, int val)
{
++minHeap->size;
int i = minHeap->size - 1;
while (i && (val < minHeap->harr[(i - 1) / 2])) {
minHeap->harr[i] = minHeap->harr[(i - 1) / 2];
i = (i - 1) / 2;
}
minHeap->harr[i] = val;
}
// A standard function to build min-heap
void buildMinHeap(struct MinHeap* minHeap)
{
int n = minHeap->size - 1;
int i;
for (i = (n - 1) / 2; i >= 0; --i)
minHeapify(minHeap, i);
}
// Creates a min-heap of capacity
// equal to size and inserts all values
// from len[] in it. Initially, size
// of min heap is equal to capacity
struct MinHeap* createAndBuildMinHeap(
int len[], int size)
{
struct MinHeap* minHeap = createMinHeap(size);
for (int i = 0; i < size; ++i)
minHeap->harr[i] = len[i];
minHeap->size = size;
buildMinHeap(minHeap);
return minHeap;
}
// The main function that returns
// the minimum cost to connect n
// ropes of lengths stored in len[0..n-1]
int minCost(int len[], int n)
{
int cost = 0; // Initialize result
// Create a min heap of capacity
// equal to n and put all ropes in it
struct MinHeap* minHeap = createAndBuildMinHeap(len, n);
// Iterate while size of heap doesn't become 1
while (!isSizeOne(minHeap)) {
// Extract two minimum length
// ropes from min heap
int min = extractMin(minHeap);
int sec_min = extractMin(minHeap);
cost += (min + sec_min); // Update total cost
// Insert a new rope in min heap
// with length equal to sum
// of two extracted minimum lengths
insertMinHeap(minHeap, min + sec_min);
}
// Finally return total minimum
// cost for connecting all ropes
return cost;
}
// Driver program to test above functions
int main()
{
int len[] = { 4, 3, 2, 6 };
int size = sizeof(len) / sizeof(len[0]);
cout << "Total cost for connecting ropes is "
<< minCost(len, size);
return 0;
}
Java
// Java program to connect n
// ropes with minimum cost
// A class for Min Heap
class MinHeap {
int[] harr; // Array of elements in heap
int heap_size; // Current number of elements in min heap
int capacity; // maximum possible size of min heap
// Constructor: Builds a heap from
// a given array a[] of given size
public MinHeap(int a[], int size)
{
heap_size = size;
capacity = size;
harr = a;
int i = (heap_size - 1) / 2;
while (i >= 0) {
MinHeapify(i);
i--;
}
}
// A recursive method to heapify a subtree
// with the root at given index
// This method assumes that the subtrees
// are already heapified
void MinHeapify(int i)
{
int l = left(i);
int r = right(i);
int smallest = i;
if (l < heap_size && harr[l] < harr[i])
smallest = l;
if (r < heap_size && harr[r] < harr[smallest])
smallest = r;
if (smallest != i) {
swap(i, smallest);
MinHeapify(smallest);
}
}
int parent(int i) { return (i - 1) / 2; }
// to get index of left child of node at index i
int left(int i) { return (2 * i + 1); }
// to get index of right child of node at index i
int right(int i) { return (2 * i + 2); }
// Method to remove minimum element (or root) from min heap
int extractMin()
{
if (heap_size <= 0)
return Integer.MAX_VALUE;
if (heap_size == 1) {
heap_size--;
return harr[0];
}
// Store the minimum value, and remove it from heap
int root = harr[0];
harr[0] = harr[heap_size - 1];
heap_size--;
MinHeapify(0);
return root;
}
// Inserts a new key 'k'
void insertKey(int k)
{
if (heap_size == capacity) {
System.out.println("Overflow: Could not insertKey");
return;
}
// First insert the new key at the end
heap_size++;
int i = heap_size - 1;
harr[i] = k;
// Fix the min heap property if it is violated
while (i != 0 && harr[parent(i)] > harr[i]) {
swap(i, parent(i));
i = parent(i);
}
}
// A utility function to check
// if size of heap is 1 or not
boolean isSizeOne()
{
return (heap_size == 1);
}
// A utility function to swap two elements
void swap(int x, int y)
{
int temp = harr[x];
harr[x] = harr[y];
harr[y] = temp;
}
// The main function that returns the
// minimum cost to connect n ropes of
// lengths stored in len[0..n-1]
static int minCost(int len[], int n)
{
int cost = 0; // Initialize result
// Create a min heap of capacity equal
// to n and put all ropes in it
MinHeap minHeap = new MinHeap(len, n);
// Iterate while size of heap doesn't become 1
while (!minHeap.isSizeOne()) {
// Extract two minimum length ropes from min heap
int min = minHeap.extractMin();
int sec_min = minHeap.extractMin();
cost += (min + sec_min); // Update total cost
// Insert a new rope in min heap with length equal to sum
// of two extracted minimum lengths
minHeap.insertKey(min + sec_min);
}
// Finally return total minimum
// cost for connecting all ropes
return cost;
}
// Driver code
public static void main(String args[])
{
int len[] = { 4, 3, 2, 6 };
int size = len.length;
System.out.println("Total cost for connecting ropes is " + minCost(len, size));
}
};
// This code is contributed by shubham96301
C#
// C# program to connect n ropes with minimum cost
using System;
// A class for Min Heap
class MinHeap {
int[] harr; // Array of elements in heap
int heap_size; // Current number of elements in min heap
int capacity; // maximum possible size of min heap
// Constructor: Builds a heap from
// a given array a[] of given size
public MinHeap(int[] a, int size)
{
heap_size = size;
capacity = size;
harr = a;
int i = (heap_size - 1) / 2;
while (i >= 0) {
MinHeapify(i);
i--;
}
}
// A recursive method to heapify a subtree
// with the root at given index
// This method assumes that the subtrees
// are already heapified
void MinHeapify(int i)
{
int l = left(i);
int r = right(i);
int smallest = i;
if (l < heap_size && harr[l] < harr[i])
smallest = l;
if (r < heap_size && harr[r] < harr[smallest])
smallest = r;
if (smallest != i) {
swap(i, smallest);
MinHeapify(smallest);
}
}
int parent(int i) { return (i - 1) / 2; }
// to get index of left child of node at index i
int left(int i) { return (2 * i + 1); }
// to get index of right child of node at index i
int right(int i) { return (2 * i + 2); }
// Method to remove minimum element (or root) from min heap
int extractMin()
{
if (heap_size <= 0)
return int.MaxValue;
if (heap_size == 1) {
heap_size--;
return harr[0];
}
// Store the minimum value, and remove it from heap
int root = harr[0];
harr[0] = harr[heap_size - 1];
heap_size--;
MinHeapify(0);
return root;
}
// Inserts a new key 'k'
void insertKey(int k)
{
if (heap_size == capacity) {
Console.WriteLine("Overflow: Could not insertKey");
return;
}
// First insert the new key at the end
heap_size++;
int i = heap_size - 1;
harr[i] = k;
// Fix the min heap property if it is violated
while (i != 0 && harr[parent(i)] > harr[i]) {
swap(i, parent(i));
i = parent(i);
}
}
// A utility function to check
// if size of heap is 1 or not
Boolean isSizeOne()
{
return (heap_size == 1);
}
// A utility function to swap two elements
void swap(int x, int y)
{
int temp = harr[x];
harr[x] = harr[y];
harr[y] = temp;
}
// The main function that returns the
// minimum cost to connect n ropes of
// lengths stored in len[0..n-1]
static int minCost(int[] len, int n)
{
int cost = 0; // Initialize result
// Create a min heap of capacity equal
// to n and put all ropes in it
MinHeap minHeap = new MinHeap(len, n);
// Iterate while size of heap doesn't become 1
while (!minHeap.isSizeOne()) {
// Extract two minimum length ropes from min heap
int min = minHeap.extractMin();
int sec_min = minHeap.extractMin();
cost += (min + sec_min); // Update total cost
// Insert a new rope in min heap with length equal to sum
// of two extracted minimum lengths
minHeap.insertKey(min + sec_min);
}
// Finally return total minimum
// cost for connecting all ropes
return cost;
}
// Driver code
public static void Main(String[] args)
{
int[] len = { 4, 3, 2, 6 };
int size = len.Length;
Console.WriteLine("Total cost for connecting ropes is " + minCost(len, size));
}
};
// This code is contributed by Arnab Kundu
C++
#include
using namespace std;
int minCost(int arr[], int n)
{
// Create a priority queue
// https:// www.geeksforgeeks.org/priority-queue-in-cpp-stl/
// By default 'less' is used which is for decreasing order
// and 'greater' is used for increasing order
priority_queue, greater > pq(arr, arr + n);
// Initialize result
int res = 0;
// While size of priority queue is more than 1
while (pq.size() > 1) {
// Extract shortest two ropes from pq
int first = pq.top();
pq.pop();
int second = pq.top();
pq.pop();
// Connect the ropes: update result and
// insert the new rope to pq
res += first + second;
pq.push(first + second);
}
return res;
}
// Driver program to test above function
int main()
{
int len[] = { 4, 3, 2, 6 };
int size = sizeof(len) / sizeof(len[0]);
cout << "Total cost for connecting ropes is " << minCost(len, size);
return 0;
}
Java
// Java program to connect n
// ropes with minimum cost
import java.util.*;
class ConnectRopes {
static int minCost(int arr[], int n)
{
// Create a priority queue
PriorityQueue pq = new PriorityQueue();
// Adding items to the pQueue
for (int i = 0; i < n; i++) {
pq.add(arr[i]);
}
// Initialize result
int res = 0;
// While size of priority queue
// is more than 1
while (pq.size() > 1) {
// Extract shortest two ropes from pq
int first = pq.poll();
int second = pq.poll();
// Connect the ropes: update result
// and insert the new rope to pq
res += first + second;
pq.add(first + second);
}
return res;
}
// Driver program to test above function
public static void main(String args[])
{
int len[] = { 4, 3, 2, 6 };
int size = len.length;
System.out.println("Total cost for connecting"
+ " ropes is " + minCost(len, size));
}
}
// This code is contributed by yash_pec
Python3
# Python3 program to connect n
# ropes with minimum cost
import heapq
def minCost(arr, n):
# Create a priority queue out of the
# given list
heapq.heapify(arr)
# Initializ result
res = 0
# While size of priority queue
# is more than 1
while(len(arr) > 1):
# Extract shortest two ropes from arr
first = heapq.heappop(arr)
second = heapq.heappop(arr)
#Connect the ropes: update result
# and insert the new rope to arr
res += first + second
heapq.heappush(arr, first + second)
return res
# Driver code
if __name__ == '__main__':
lengths = [ 4, 3, 2, 6 ]
size = len(lengths)
print("Total cost for connecting ropes is " +
str(minCost(lengths, size)))
# This code is contributed by shivampatel5
C#
// C# program to connect n
// ropes with minimum cost
using System;
using System.Collections.Generic;
public class ConnectRopes
{
static int minCost(int []arr, int n)
{
// Create a priority queue
List pq = new List();
// Adding items to the pQueue
for (int i = 0; i < n; i++)
{
pq.Add(arr[i]);
}
// Initialize result
int res = 0;
// While size of priority queue
// is more than 1
while (pq.Count > 1)
{
pq.Sort();
// Extract shortest two ropes from pq
int first = pq[0];
int second = pq[1];
pq.RemoveRange(0, 2);
// Connect the ropes: update result
// and insert the new rope to pq
res += first + second;
pq.Add(first + second);
}
return res;
}
// Driver program to test above function
public static void Main(String []args)
{
int []len = { 4, 3, 2, 6 };
int size = len.Length;
Console.WriteLine("Total cost for connecting"
+ " ropes is " + minCost(len, size));
}
}
// This code is contributed by Rajput-Ji
输出:
Total cost for connecting ropes is 29
复杂度分析:
- 时间复杂度: O(nLogn),假设我们使用O(nLogn)排序算法。请注意,诸如插入和提取之类的堆操作需要O(Logn)时间。
- 辅助复杂度: O(n),将值存储在最小堆中所需的空间
算法范式:贪婪算法
在C++中使用STL的简单实现
这使用STL中可用的priority_queue。感谢Pango89提供以下代码。方法和算法保持不变。最小堆将替换为优先级队列。
C++
#include
using namespace std;
int minCost(int arr[], int n)
{
// Create a priority queue
// https:// www.geeksforgeeks.org/priority-queue-in-cpp-stl/
// By default 'less' is used which is for decreasing order
// and 'greater' is used for increasing order
priority_queue, greater > pq(arr, arr + n);
// Initialize result
int res = 0;
// While size of priority queue is more than 1
while (pq.size() > 1) {
// Extract shortest two ropes from pq
int first = pq.top();
pq.pop();
int second = pq.top();
pq.pop();
// Connect the ropes: update result and
// insert the new rope to pq
res += first + second;
pq.push(first + second);
}
return res;
}
// Driver program to test above function
int main()
{
int len[] = { 4, 3, 2, 6 };
int size = sizeof(len) / sizeof(len[0]);
cout << "Total cost for connecting ropes is " << minCost(len, size);
return 0;
}
Java
// Java program to connect n
// ropes with minimum cost
import java.util.*;
class ConnectRopes {
static int minCost(int arr[], int n)
{
// Create a priority queue
PriorityQueue pq = new PriorityQueue();
// Adding items to the pQueue
for (int i = 0; i < n; i++) {
pq.add(arr[i]);
}
// Initialize result
int res = 0;
// While size of priority queue
// is more than 1
while (pq.size() > 1) {
// Extract shortest two ropes from pq
int first = pq.poll();
int second = pq.poll();
// Connect the ropes: update result
// and insert the new rope to pq
res += first + second;
pq.add(first + second);
}
return res;
}
// Driver program to test above function
public static void main(String args[])
{
int len[] = { 4, 3, 2, 6 };
int size = len.length;
System.out.println("Total cost for connecting"
+ " ropes is " + minCost(len, size));
}
}
// This code is contributed by yash_pec
Python3
# Python3 program to connect n
# ropes with minimum cost
import heapq
def minCost(arr, n):
# Create a priority queue out of the
# given list
heapq.heapify(arr)
# Initializ result
res = 0
# While size of priority queue
# is more than 1
while(len(arr) > 1):
# Extract shortest two ropes from arr
first = heapq.heappop(arr)
second = heapq.heappop(arr)
#Connect the ropes: update result
# and insert the new rope to arr
res += first + second
heapq.heappush(arr, first + second)
return res
# Driver code
if __name__ == '__main__':
lengths = [ 4, 3, 2, 6 ]
size = len(lengths)
print("Total cost for connecting ropes is " +
str(minCost(lengths, size)))
# This code is contributed by shivampatel5
C#
// C# program to connect n
// ropes with minimum cost
using System;
using System.Collections.Generic;
public class ConnectRopes
{
static int minCost(int []arr, int n)
{
// Create a priority queue
List pq = new List();
// Adding items to the pQueue
for (int i = 0; i < n; i++)
{
pq.Add(arr[i]);
}
// Initialize result
int res = 0;
// While size of priority queue
// is more than 1
while (pq.Count > 1)
{
pq.Sort();
// Extract shortest two ropes from pq
int first = pq[0];
int second = pq[1];
pq.RemoveRange(0, 2);
// Connect the ropes: update result
// and insert the new rope to pq
res += first + second;
pq.Add(first + second);
}
return res;
}
// Driver program to test above function
public static void Main(String []args)
{
int []len = { 4, 3, 2, 6 };
int size = len.Length;
Console.WriteLine("Total cost for connecting"
+ " ropes is " + minCost(len, size));
}
}
// This code is contributed by Rajput-Ji
输出:
Total cost for connecting ropes is 29
复杂度分析:
- 时间复杂度: O(nLogn),假设我们使用O(nLogn)排序算法。
请注意,诸如插入和提取之类的堆操作需要O(Logn)时间。 - 辅助复杂度: O(n)。
在最小堆中存储值所需的空间