Условие
Условие задачи отражает Вашу задачу: необходимо просто сложить числа. Но это будет унизительно если Вас попросят просто написать такую программу на языке C/C++ для заданного множества чисел. Давайте внесем в задачу оттенок изобретательности.
Введем понятие стоимости для операции сложения. Стоимость сложения двух чисел положим равным их сумме. Например, сложить числа $1$ и $10$ стоит $11$. Стоимость сложения $1,$ $2$ равна $3$. Складывать числа можно разными способами:
- $1 + 2 = 3 \left(стоимость = 3\right), 3 + 3 = 6 \left(стоимость = 6\right), Всего = 9 $
- $1 + 3 = 4 \left(стоимость = 4\right), 2 + 4 = 6 \left(стоимость = 6\right), Всего = 10 $
- $2 + 3 = 5 \left(стоимость = 5\right), 1 + 5 = 6 \left(стоимость = 6\right), Всего = 11 $
Надеемся, Вы поняли Вашу задачу. Вам необходимо сложить все числа так, чтобы суммарная стоимость их сложения была наименьшая.
Входные данные
Начинаются целым числом $n (2 \leqslant n \leqslant 100000)$, за которым следуют $n$ целых неотрицательных чисел (все числа меньше $100000$).
Выходные данные
Вывести наименьшую стоимость сложения всех чисел.
Тесты
| Ввод | Вывод | 
| $4$ $10$ $12$ $13$ $11$ | $92$ | 
| $5$ $100$ $11$ $8$ $30$ $12$ | $272$ | 
| $4$ $2$ $2$ $2$ $2$ | $16$ | 
| $6$ $1$ $2$ $3$ $4$ $5$ $6$ | $51$ | 
Код
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <iostream> #include <queue> using namespace std; int main() {     priority_queue <long long> nums;     long long n;     cin >> n;     long long number = 0;     for (int i = 0; i < n; i++) {         cin >> number;         nums.push(-number);     }     long long min_sum = 0;     long long a = 0;     long long b = 0;     while ( !nums.empty() )     {         a = nums.top();         nums.pop();         if (nums.empty()) break;         b = nums.top();         nums.pop();         min_sum -= a+b;         nums.emplace(a+b);     }     cout << " " << min_sum;     return 0; } | 
Решение
Стоимость сложения всех чисел будет минимальной, если на каждом следующем шаге мы будем складывать два наименьшие числа из множества $A$, состоящего из данного ряда чисел и уже вычисленных «частичных сумм». Таким образом, каждый шаг цикла поиска минимальной стоимости сложения будет состоять из нахождения двух минимальных чисел из множества, удаления этих чисел из множества $A$ и добавления в него результата их суммирования. В специальную переменную $min\_sum$ будем также каждый раз добавлять результат этого суммирования. Таким образом, количество элементов во множестве будет с каждым шагом уменьшаться на одно, и в конце, когда в нем останется единственный элемент, переменная $min\_sum$ будет содержать искомую стоимость сложения всех чисел.
Реализовать такой код достаточно просто, если реализовать множество $A$ в виде очереди с приоритетом. Так как в задаче нужны минимальные элементы множества, а очередь располагает элементы в порядке их увеличения, то будем хранить в ней не сами элементы множества $A$, а противоположные им числа.
Ссылки
Условие на e-olymp.com
Код на ideone.com
