Задача о ранце. Программивание на языке СИ.

Известен вес P[1], P[2], ,,,, P[n] каждого из n предметов.
Как разместить их в наименьшем числе рюкзаков, если грузоподъёмность каждого рюкзака равна q.



Просмотреть код программы.

Скачать архив программы.

Алгоритм работы программы.

Описание работы программы:

Программа проверяет, существует ли в папке с программой текстовый файл store.txt из действительных чисел, которые представляют собой вес каждого предмета, и если этого файла нет, то создаёт его. При создании файла требуется ввести количество всех предметов n и максимальную величину веса предмета, соответствующую минимальной грузоподъёмности рюкзака min. Если файл store.txt существует в папке с программой, выполняется подпрограмма, распределяющая предметы в наименьшее количество рюкзаков. Вначале количеству рюкзаков v, суммарному весу предметов w, количеству всех предметов n присваивается нулевое значение. Программа сначала подсчитывает количество всех предметов n (количество целых чисел, содержащихся в файле g). После этого выделяется память под массив целых чисел p[0..n], и все целые числа из файла store.txt записываются в массив p[n]. После этого находится максимальный элемента массива p[n], равный минимальной вместимости рюкзака min. Подсчитывается также суммарный вес всех предметов w, равный сумме всех элементов массива p(n). После этого пользователь сможет вести с клавиатуры значение минимальной вместимости рюкзака, не меньшее, чем min. Значения min, w, n, q, а также значения всех элементов массива p[n] выводятся на экран и в текстовый файл comb.txt

В начале работы программы в массиве p(n) все n чисел строго положительны, нулевых элементов нет. В процессе работы программы в порядке невозрастания числа m на экран и в файл comb.txt будут выводиться всевозможные суммы по k слагаемых, не содержащие в себе нулевых слагаемых и равные заданному числу m. Значение k количества слагаемых в этих суммах будет меняться от 1 до n. После вывода каждой такой суммы соответствующим слагаемым массива будет присваиваться нулевое значение, и следующие суммы будут состоять только из оставшихся ненулевых элементов массива. Сначала значению m будет присвоено значение вместимости рюкзака q , найдены и выведены все суммы, равные q, соответствующие рюказаку, заполненному максимально (вес всех предметов в рюкзаке равен вместимости рюкзака). После этого число m будем уменьшать на единицу и до суммы всех оставшихся ненулевых элементов массива, пока оно не станет равным нулю.

Для нахождения всевозможных сумм из из k слагаемых, равных заданному числу m, где каждое слагаемое суммы принадлежит множеству из n чисел p[1]..p[n], используется следующий алгоритм.

Вводится массив из k индексов a[i] для k слагаемых в сумме. В начальной конфигурации все эти индексы следуют по порядку друг за другом от 1 до k. Индекс i меняется при этом от 1 до k в цикле for (i=0; i<=k; i++) a[i]=i;.
Далее присваиваются нулевые значения элементам j, r.
j - переменная, указывающая, сколько элементов индексов в конце массива индексов удовлетворяют условию: a[k-j]==n-j, то есть последний элемент a[k] в списке a[1]..a[k] равен последнему номеру n , предпоследний a[k-1] равен n-1, …, j-й индекс с конца a[k-j] равен n-j. Значение переменной j будет меняться от 0 до k-1.
Далее следует большой цикл, который будет завершён тогда, когда значение переменной j станет равным k-1. Этот цикл закончится тогда, когда все k индексов в сумме станут располагаться по порядку друг за другом, и на последнем месте будет стоять индекс a(n), на предпоследнем a(n-1), …, на первом месте a(n-k+1).
Вычисляется сумма k слагаемых p[a[1]]+p[a[2]]+…+p[a[k]], и выполняется проверка, равна ли она заданному числу m. Если заданное количество элементов массива n больше заданного количества слагаемых в сумме k (k<n), то в самой первой сумме, когда слагаемые располагались по порядку друг за другом a[1]=1, a[2]=2, … a[k]=k, а j=0, условие a[k-j]==n-j не выполняется, и значение последнего индекса a[k] увеличивается на единицу (a[k-j]++), после чего снова подсчитывается сумма k слагаемых p[a[1]]+p[a[2]]+…+p[a[k]], и выполняется проверка, равна ли эта сумма равна заданному числу m.
(Цикл for (r=0; r<j; r++) a[k-j+r+1]=a[k-j+r]+1; не выполняется ни разу при условии j==0).
Так продолжается до тех пор, пока последний индекс a[k]не станет равным n.
Как только начнёт выполняться условие a[k]==n (то есть a[k-j]==n-j при j==0), значение j увеличивается на единицу и принимает значение 1.
Если заданное n значительно больше заданного k, то при j==1 условие a[k-j]==n-j не выполняется, и значение предпоследнего индекса a[k-1] увеличивается на единицу a[k-1]= a[k-1]+1 (a[k-j]++ при j==1), а значение последнего индекса устанавливается на единицу больше значения предпоследнего индекса a[k]=a[k-1]+1 (это будет достигнуто благодаря однократному выполнению цикла for (r=0; r<j; r++) a[k-j+r+1]=a[k-j+r]+1; при значениях j==1, r==0).
После этого значение j присваивается нулевое значение и повторяется цикл с увеличением на 1 последнего индекса a[k].
а определённом этапе выполнения этого алгоритма может оказаться так, что j индексов подряд, начиная с конца массива индексов, удовлетворяют следующему условию:
a[k]==n, a[k-1]==n-1, a[k-2]==n-2, a[k-3]==n-3, … , a[k-j+1]==n-j+1,
но значение a[k-j] не равно n-j. Тогда происходит увеличение на единицу этого индекса a[k-j], а следующие за ним j индексов будут расположены по порядку возрастания на 1 друг за другом, то есть
a[k-j+1]=a[k-j]+1, a[k-j+2]=a[k-j+1]+1, a[k-j+3]= a[k-j+2]+1, … , a[k-1]=a[k-2]+1; a[k]=a[k-1]+1. )
Это произойдёт благодаря выполнению j раз цикла for (r=0; r<j; r++) a[k-j+r+1]=a[k-j+r]+1).
Большой цикл завершится при выполнении условия
a(k)==n, a(k-1)==n-1, a(k-2)==n-2, …, a(1)==n-k+1 Так будут выведены всевозможные суммы из по k чисел, сумма которых равна заданному числу m.
Индекс k будет пробегать все значения от 1 до n





файл store.txt

4
4
3
3
2
2


Файл comb.txt

ООбщее количество предметов N=  6  
Вес каждого предмета:
P[ 1] =  4
P[ 2] =  4
P[ 3] =  3
P[ 4] =  3
P[ 5] =  2
P[ 6] =  2
Грузоподъёмность рюкзака =  9
Суммарный вес всех предметов = 18 
В 1 -й рюкзак вошли следующие предметы P[ 1] + P[ 3] + P[ 5] = 9
В 2 -й рюкзак вошли следующие предметы P[ 2] + P[ 4] + P[ 6] = 9

файл store.txt

22
16
24
4
8
15
11
13
15
4
15
19
27
28
14
22
4
10
20
3


Файл comb.txt

Общее количество предметов N=  20  
Вес каждого предмета:
P[ 1] = 22
P[ 2] = 16
P[ 3] = 24
P[ 4] =  4
P[ 5] =  8
P[ 6] = 15
P[ 7] = 11
P[ 8] = 13
P[ 9] = 15
P[10] =  4
P[11] = 15
P[12] = 19
P[13] = 27
P[14] = 28
P[15] = 14
P[16] = 22
P[17] =  4
P[18] = 10
P[19] = 20
P[20] =  3
Грузоподъёмность рюкзака = 42
Суммарный вес всех предметов = 294 
В 1 -й рюкзак вошли следующие предметы P[ 1] + P[19] = 42
В 2 -й рюкзак вошли следующие предметы P[ 6] + P[13] = 42
В 3 -й рюкзак вошли следующие предметы P[14] + P[15] = 42
В 4 -й рюкзак вошли следующие предметы P[ 2] + P[ 4] + P[16] = 42
В 5 -й рюкзак вошли следующие предметы P[ 3] + P[ 5] + P[18] = 42
В 6 -й рюкзак вошли следующие предметы P[ 7] + P[ 8] + P[ 9] + P[20] = 42
В 7 -й рюкзак вошли следующие предметы P[10] + P[11] + P[12] + P[17] = 42

Файл comb.txt

Общее количество предметов N=  20  
Вес каждого предмета:
P[ 1] = 22
P[ 2] = 16
P[ 3] = 24
P[ 4] =  4
P[ 5] =  8
P[ 6] = 15
P[ 7] = 11
P[ 8] = 13
P[ 9] = 15
P[10] =  4
P[11] = 15
P[12] = 19
P[13] = 27
P[14] = 28
P[15] = 14
P[16] = 22
P[17] =  4
P[18] = 10
P[19] = 20
P[20] =  3
Грузоподъёмность рюкзака = 40
Суммарный вес всех предметов = 294 
В 1 -й рюкзак вошли следующие предметы P[ 2] + P[ 3] = 40
В 2 -й рюкзак вошли следующие предметы P[ 8] + P[13] = 40
В 3 -й рюкзак вошли следующие предметы P[ 1] + P[ 4] + P[15] = 40
В 4 -й рюкзак вошли следующие предметы P[ 5] + P[10] + P[14] = 40
В 5 -й рюкзак вошли следующие предметы P[ 6] + P[ 9] + P[18] = 40
В 6 -й рюкзак вошли следующие предметы P[11] + P[16] + P[20] = 40
В 7 -й рюкзак вошли следующие предметы P[12] + P[19] = 39
В 8 -й рюкзак вошли следующие предметы P[ 7] + P[17] = 15