• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Kombinacja bez powtórzeń

0 głosów
1,556 wizyt
pytanie zadane 8 września 2021 w C i C++ przez Piotr Zenger Nowicjusz (120 p.)

Witam, chce wykonać zadanie z kombinacją bez powtórzeń ale kompletnie nie umiem ułożyć kod w oparciu o to. Znam wzór, zrobiłem już jedno zadanie z permutacją lecz nie wiem jak sformułować kod aby działał poprawnie. Chciałbym też zwrócić uwagę na to, że napisanie kodu powinienem oprzeć na pętli for.

Zadanie:
Robot kucharski Don_Giovanni_Elemental16 specjalizuje się w wytwarzaniu oryginalnej włoskiej pizzy. Proces zawsze rozpoczyna się od ułożenia ciasta, posmarowania go sosem pomidorowym oraz posypania mozzarellą. Następnie Don_Giovanni_Elemental16 układa dodatki wg zamówienia. Klient poprosił o pewną liczbę dodatków (większą od 0), obojętnie jakich. 
Uzupełnij funkcję int pizza ( int n, int k ), aby zwracała liczbę wszystkich możliwych kombinacji pizzy (w tym również tych wyjątkowo ohydnych) zakładając, że n to liczba dostępnych dodatków, a k to liczba zamówionych dodatków oraz, że każdy dodatek można w pizzy użyć najwyżej raz.

Mam również wskazówkę do tego zadania, próbowałem coś z tym zrobić ale nie rozumiem tego:

We wzorze na liczbę kombinacji trzy razy występuje wyrażenie z silnią. Dla ułatwienia i dla lepszej czytelności kodu, przypisz wyniki tych wyrażeń trzem różnym zmiennym - np. n_silnia, k_silnia, n_minus_k_silnia. Mając wartości tych trzech zmiennych łatwo obliczysz liczbę kombinacji - z silnią poradziłeś już sobie w poprzednim ćwiczeniu. Uważaj, aby Twoje pętle wykonały się odpowiednią ilość razy. Pamiętaj, że inkrementacja licznika w nagłówku pętli następuje PO wykonaniu pętli, a nie przed (w przeciwieństwie do sprawdzenia warunku).

Z góry dziękuje za podpowiedź, podsyłam również początek kodu.

int pizza( int n, int k )
{
    return 0;
}

 

komentarz 8 września 2021 przez wojtek_suchy Mądrala (6,880 p.)
Ale jak znasz wzor to w czym problem?
komentarz 8 września 2021 przez Piotr Zenger Nowicjusz (120 p.)

Generalnie to wiem, że musze użyć permutacji na n oraz na k, przynajmniej tak mi się wydaje. Niekoniecznie wiem jak to zrobić to na 2 różnych zmiennych.

int pizza( int n, int k )
{
    int n_silnia, k_silnia, n_minus_k_silnia,  C;
    
    
    for(int i = 1; i <= n; i++)
    {
    n_silnia *= i;
    n = n_silnia;
    }
    
    for(int i; i <= k; i++)
    {
    k_silnia *= i;
    k = k_silnia;
    }
 
    n_minus_k_silnia = n - k;
    
    C = n / ( k * n_minus_k_silnia);
 
    return C;
}

To jest kod który mi wyszedł. Domyślam się, że jest kompletnie zły ale chce pokazać wmiarę mój tok myślenia żeby można było mi dać jakąś wskazówkę. Nie wiem czy mam w jakiś sposób zwrócić permutacje wczesniej k i n albo czy w ogóle mogę uzywać dwa razy i do n i k, czy może źle obliczyłem (n-k)!.

 

komentarz 8 września 2021 przez dziablo Użytkownik (940 p.)
Hej,

co do linii gdzie deklarujesz zmienne, w C i C++ w ten sposób zadeklarowane zmienne będą miały losowa wartość, zainicjalizuj je.

Co do pętli gdzie używasz zmiennej i, używasz jej tak

for(int i = 1; i <= n; i++)

co znaczy. ze zmienna i będzie istniała tylko dla tej pętli, a później zostanie usunięta.

Nawet gdyby nie była usunięta, to na początku pętli przypisujesz do i 1, wiec spokojnie możesz jej użyć jeszcze raz w drugiej pętli.

 

Co jest nie tak w pętli to, że ma ona działać, dopóki i będzie mniejsze od n, ale w każdej iteracji pętli przypisujesz do n aktualna wartość n_silnia, która będzie zawsze większa lub równa i, wiec skończysz z pętla, która będzie działać w nieskończoność.

Nie modyfikuj k i n, wyniki operacji silni masz w n_silnia i k_silnia.

Z wzorem C = ... nie pomogę, bo jestem zerem z matematyki :)

Pozdro
1
komentarz 8 września 2021 przez Piotr Zenger Nowicjusz (120 p.)

Dzięki wielkie za pomoc! Po kilkunastu próbach wreszcie się udało.

Ostatecznie zrobiłem tak:

int pizza( int n, int k )
{
    int n_silnia=1, k_silnia=1, n_minus_k_silnia=1, n_minus_k;
    int C=0;
    
    n_minus_k = n - k;
    
    
    for(int i=1; i <= n; i++)
    {
        n_silnia *= i;
    }
    
    for(int i=1; i <= k; i++)
    {
        k_silnia *= i;
    }
    
    for(int i=1; i<= n_minus_k; i++)
    {
        n_minus_k_silnia *= i;
    }
    
 
    C = n_silnia / ( k_silnia * n_minus_k_silnia);
 
    return C;
}

Faktycznie trzeba było nadać wartości zmiennym oraz odpowiednio ułożyć pętle. Jeszcze raz dzięki za pomoc!

komentarz 9 września 2021 przez dziablo Użytkownik (940 p.)
Super, ze się udało, nie wiem, czy cię interesują dodatkowe uwagi, ale wstawiam:

Deklaruj zmienne, jak najbliżej miejsca, gdzie są definiowane. Konwencja, jakiej używasz pochodzi, ze starego C, gdzie trzeba było wszystkie zmienne deklarować na początku albo program się nie kompilował.

 

przykładowo  "C = n_silnia / ( k_silnia * n_minus_k_silnia); "

może być "int C = n_silnia / ( k_silnia * n_minus_k_silnia); "

 

Ze zmiennymi jak n_silnia, gorzej, bo są wypełniane w pętli, ale tez lepiej zaraz przed forem zainicjalizowac zmienna.

x3 z rzedu wykonujesz te sama operacje liczenia silni, wiec to się prosi, żeby wyciągnąć ten kod do osobnej metody.

Wtedy problem ze zmiennymi jak n_silnia tez się rozwiązuje, bo możesz napisać

int k_silnia = silnia(k);

 

W pętli liczącej silnie możesz przypisać zmiennej i 2, zamiast 1 żeby pominąć nic nierobiąca pierwsza iteracje pętli k_silnia *= i; (k_silnia = 1 * 1)

1 odpowiedź

–1 głos
odpowiedź 9 września 2021 przez TOM_CPP Pasjonat (22,640 p.)
edycja 9 września 2021 przez TOM_CPP

Bardziej optymalny kod na obliczanie kombinacji nie może liczyć bezpośrednio silni, gdyż już przy niewielkich wartościach nastąpi przekroczenie zakresu zmiennych - spróbuj wywołać pizza(100,5).  

To co powinieneś zrobić to skrócić wzór i  wykonywać każde mnożenie równocześnie z dzieleniem.

(N)/1 * (N-1)/2 * (N-2)/3 * ... * (N-K+1)/K

size_t combination( int n , int k )
{
    if( k == 0 ) return 1;

    /*
     Dla dużych wartości k ( większych od n / 2 ) 
     w celu dodatkowego zmniejszenia ilości obliczeń 
     możemy skorzystać z własności kombinacji:     
     kombinacja( n , k ) = kombinacja( n , n - k )
    */
    if( k > n / 2 ) return combination( n , n - k );

    size_t result {1};

    for( int i {1} ; i <= k ; ++i )
    {
        result *= n - i + 1;
        result /= i;
    }

    return result;
}

 

Podobne pytania

0 głosów
4 odpowiedzi 4,134 wizyt
pytanie zadane 27 lutego 2019 w C i C++ przez de1vee Nowicjusz (220 p.)
0 głosów
2 odpowiedzi 1,135 wizyt
pytanie zadane 28 czerwca 2016 w C i C++ przez 1naswiecie Początkujący (410 p.)
+1 głos
4 odpowiedzi 655 wizyt
pytanie zadane 4 stycznia 2022 w C# przez niezalogowany

93,728 zapytań

142,668 odpowiedzi

323,283 komentarzy

63,287 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...