Loading...
VitaminX avatar VitaminX 7 Точки

Problem 12. * Zero Subset, Условни конструкции, Basics Sep 2015

Здравейте Колеги,

Надявам се някой от вас да успее да ми отговори на въпрос относно задача 12 от домашното за Условни конструкции.

We are given 5 integer numbers. Write a program that finds all subsets of these numbers whose sum is 0. Assume that repeating the same subset several times is not a problem.

Това, което ме притеснява е, че пише „ ...repeating the same subset several times is not a problem“, но в примерите, комбинацията 1 1 1 -1 -1, не дава всички комбинации а само: 

1 + -1 = 0

1 + 1 + -1 + -1 = 0

1 + -1 + 1 + -1 = 0

при мен излизат:

1 + -1 = 0
1 + -1 = 0
1 + -1 = 0
1 + -1 = 0
1 + -1 = 0
1 + 1 + -1 + -1 = 0
1 + 1 + -1 + -1 = 0

Подозирам, че това не е правилен резултат, но бих искал да попитам и за вашето мнение преди да преправям решението.

Благодаря!

0
Programming Basics 14/10/2015 16:28:25
flashestswag avatar flashestswag 66 Точки

Здравей не си забелязал, че в задачата под изброените решения има многоточие. Тоест не са ги  изброили всичките.
 
1 + -1 = 0
1 + 1 + -1 + -1 = 0
1 + -1 + 1 + -1 = 0

А това, че се получават неуникални сборове даващи 0, не трябва да те притеснява, това е  напълно нормално, тъй като има повтарящи се числа в първоначално даденото множество, но в  действителност те са си напълно уникални, защото при решаването на задачата ти трябва да  направиш всички комбинации между първото, второто, третото, четвъртото и петото число така,  а когато има повтарящи се числа като сега, просто се получават повторения на повтарящите се  числа участващи в нулевия сбор. 

В нашият случай имаме:
            
    int[] numbers = { 1, 1, 1, -1, -1 };

Комбинациите от 2 числа даващи сбор 0, в случая са:
1. 1 - 1 = 0
2. 1 - 1 = 0
3. 1 - 1 = 0
4. 1 - 1 = 0
5. 1 - 1 = 0
6. 1 - 1 = 0

Те са си уникални, защото това всъщност са:
1. първото число + четвъртото число = 0
2. първото число + петото число = 0
3. второто число + четвъртото число = 0
4. второто число + петото число = 0
5. третото число + четвъртото число = 0
6. третото число + петото число = 0

или

1. numbers[0] + numbers[3] = 0
2. numbers[0] + numbers[4] = 0
3. numbers[1] + numbers[3] = 0
4. numbers[1] + numbers[4] = 0
5. numbers[2] + numbers[3] = 0
6. numbers[2] + numbers[4] = 0

Аз съм решил задачата с битове.
Използвам битова маскa.
В битовата маска, бит със стойност 1 означава числото участва в новото подмножество, бит със  стойност 0 означава числото не участва в новото подмножество.
Битовата маска всъщност са ми коефициентите, пред всяко едно от дадените числа.

Ето и решенията на задачата:

числа:           1, 1, 1, -1, -1

битова маска:    1  0  0   1   0

резултат:        1        -1      = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    1  0  0   0   1

резултат:        1            -1  = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    0  1  0   1   0

резултат:           1     -1      = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    0  1  0   0   1

резултат:           1         -1  = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    0  0  1   1   0

резултат:              1  -1      = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    0  0  1   0   1

резултат:              1      -1  = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    1  1  0   1   1

резултат:        1+ 1     -1  -1  = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    1  0  1   1   1

резултат:        1+    1  -1  -1  = 0

 

числа:           1, 1, 1, -1, -1

битова маска:    0  1  1   1   1

резултат:           1+ 1  -1  -1  = 0

Общо 9 възможни комбинации, даващи сбор 0.

А ето и кратко решение и описание как се стига до горните решения:

int coefficients = 0 //Това ми е битовата маска в случа само нули в битовете 

0 0 0 0 0 - битовете на цялото число 0

0 0 0 0 1 - битовете на цялото число 1

0 0 0 1 0 - битовете на цялото число 2

0 0 0 1 1 - битовете на цялото число 3

0 0 1 0 0 - битовете на цялото число 4

0 0 1 0 1 - битовете на цялото число 5

0 0 1 1 0 - битовете на цялото число 6

0 0 1 1 1 - битовете на цялото число 7

0 1 0 0 0 - битовете на цялото число 8

0 1 0 0 1 - битовете на цялото число 9

0 1 0 1 0 - битовете на цялото число 10

0 1 0 1 1 - битовете на цялото число 11

0 1 1 0 0 - битовете на цялото число 12

0 1 1 0 1 - битовете на цялото число 13

0 1 1 1 0 - битовете на цялото число 14

0 1 1 1 1 - битовете на цялото число 15

1 0 0 0 0 - битовете на цялото число 16

1 0 0 0 1 - битовете на цялото число 17

1 0 0 1 0 - битовете на цялото число 18

1 0 0 1 1 - битовете на цялото число 19

1 0 1 0 0 - битовете на цялото число 20

1 0 1 0 1 - битовете на цялото число 21

1 0 1 1 0 - битовете на цялото число 22

1 0 1 1 1 - битовете на цялото число 23

1 1 0 0 0 - битовете на цялото число 24

1 1 0 0 1 - битовете на цялото число 25

1 1 0 1 0 - битовете на цялото число 26

1 1 0 1 1 - битовете на цялото число 27

1 1 1 0 0 - битовете на цялото число 28

1 1 1 0 1 - битовете на цялото число 29

1 1 1 1 0 - битовете на цялото число 30

1 1 1 1 1 - битовете на цялото число 31

Формулата за броя на всички възможни комбинации е:
2^n - където n = броя на елементите на първоначално даденото множество.

В в случая множество с  5 елемента, а именно числата { 1, 1, 1, -1, -1 };
И се получават 2^5 = 32 възможни комбинации.

Като ние започваме от 0 до ((2^n) -1) = Общо 2^n комбинации от числата.
В нашият случай от 0 до 31. Общо 32 комбинации от числата

Това са всички възможни комбинации като при:
0 0 0 0 0 - не участва нито едно от числата (така нареченото празно множество, тоест такова  което е без елементи вътре в себе си, няма нито един елемент, празно) (имаме множество с 0  елемента)

0 0 0 0 1 - участва само най-дясното число (имаме множество с 1 елемент)

0 0 0 1 1 - участват само двете най-десни числа (имаме множество с 2 елемента)

1 0 0 1 1 - участват само най-лявото число и двете най-десни числа (имаме множество с 3  елемента)

1 1 1 1 1 - участват всички числа (имаме множество с 5 елемента)

и така нататък..


Както виждате ако си сложим на coefficients стойност 0 и после започнем да го увеличаваме с  единица, като стигнем до 31 включително ще получим всички възможни комбинации от битове,  сътоветно всички комбинации(подмножества) от числа, които можем да образуваме. Само, че в  случая сме сложили на coefficients 31 и намаляваме до 1 включително, което не променя решенията, просто  ще излизат в обратен ред, на този, който биха излезли ако бяхме започнали с 0 и увеличаме до  31. Само две забележки не стигаме до 0, а до 1, нулата не я използваме защото при нея не  участва нито един от елементите на нашето първоначално множество. Също така не използваме и  подмножествата които имат само 1 елемент, тоест това са стойностите на coefficients със сетнат само един бит в цялото число. Под  сетнат само един бит в цялото число, имам предвид, че имаме само 1 бит със стойност 1-ца в цялото число. В  задачата по-долу първо проверяваме дали в coefficients има сетнат само 1 бит, и ако това е  така, тогава прескачаме тази итерация на цикъла с командата continue; Това което continue  прави е, отива директно в края на цикъла. От там нататък е ясно, прави се декрементацията на  coefficients (coefficients--) и отново се изпълнява тялото на цикъла.

int[] numbers = { 1, 1, 1, -1, -1 };

int coefficientCombinations = (int) Math.Pow(2, numbers.Length) - 1;

for (int coefficients = coefficientCombinations; coefficients > 0; coefficients--)

{

    if(onlyOneBitSet(coefficients))

    {

        continue;

    }

    int sum = 0;

    for (int index = 0; index < numbers.Length; index++)

    {

        int bitIndex = (numbers.Length - 1) - index;

        int numberIndex = index;

        int coefficient = getBit(coefficients, bitIndex);

        sum += coefficient * numbers[numberIndex];

    }

    if (sum == 0)

    {

        //Print the Sum

    }

}


static int getBit(int coefficients, int bitIndex)

{

    return (coefficients >> bitIndex) & 1;

}

static bool onlyOneBitSet(int coefficients)

{

    int setBitCount = 0;

    int highestBit = 31;

    for(int i = 0; i <= highestBit; i++)

    {

        if(((coefficients >> i) & 1) == 1)

        {

            setBitCount++;

        }

    }

   if(setBitCount == 1)

    {

        return true;

    }

    else

    {

        return false;

    }

}

 

 

 

4
15/10/2015 12:21:45
VitaminX avatar VitaminX 7 Точки

Здравей, благодаря, за пояснението. Всъщност бях забелязал точките, но си мислех, че трябва да има точки и между първата комбинация от 2 числа и тази от четири. Т.е.

1 + -1 = 0

...

1 + 1 + -1 + -1 = 0

1 + -1 + 1 + -1 = 0

...

Относно твоето решение, мога ли да те помоля, да го пуснеш кода някъде другаде, защото форматирането е прецакано. Не е чак такъв проблем, но ако някой друг иска да го види, би било много по-четливо. Благодаря!

0
15/10/2015 15:54:59
flashestswag avatar flashestswag 66 Точки

Това е горното непълно решение, в което не е описано как се разпечатват числата образуващи нулев сбор: http://pastebin.com/MDkgpmgV

Това е пълното работещо решение: http://pastebin.com/uXSG4kcF

2
15/10/2015 19:59:29
slavi.g.slavchev avatar slavi.g.slavchev 45 Точки

Здравейте.

Ако няма повторения на елементите (например при числа 5 -5 4 -4 10, да се проверяват 5 -5, -5 5, т.н.), то при равни числа в инпута би трябвало да е ОК, както спомена и flashest.

Аз съм ползвал генерирани "отвън" комбинации, но може би и те ползват побитовия алгоритъм, който най-вероятно е най-бързият.

Задачи с комбинации съм имал и в практиката, когато ни ги преподаваха в гимназия, не осъзнавах, че някога ще ми потрябват :)

Моето решение:

http://pastebin.com/JDmbwu9x

3
19/10/2015 00:45:41
flashestswag avatar flashestswag 66 Точки

Много ми хареса твоето решение, Слави :) Поздрави!
Най-много ми допадна, как с един ред образуваш комбинацията за печат :)

tempstring += inputNumbers[jaggedIndices[i][j]].ToString() + (j == jaggedIndices[i].Length-1 ? " = 0" : " + ");

След лекцията за цикли ми дойде още едно по-лесно решение на задачата. И решението е като твойто Слави, генерира всички уникални комбинации даващи 0. Само, че тия индекси не ги пишеш на ръка във  int[][] jaggedIndices, а ги генерират 5 вложени цикъла :)

Ето виж: http://pastebin.com/1jPLeiFg

1
22/10/2015 20:55:49
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.