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

Problem collatza

Object Storage Arubacloud
0 głosów
3,059 wizyt
pytanie zadane 8 maja 2017 w C i C++ przez chucksqll Stary wyjadacz (12,930 p.)

Witam mam problem nie tak bardzo ze samym zadaniem jak ze zrozumieniem dlaczego nie mogę tak zrobić(słabo idą mi funkcje), dlatego kategoria c i c++.


#include <iostream>

int x(int n)
{
    if(x(n)==1)
        return n;

    else
        return x(n+1);

}
int n=0;
using namespace std;
int main()
{
    if(x(n)%2==0)
    {
        x(n+1)=x(n)/2;
    }
    if(x(n)%2!=0)
    {
        x(n+1)=(3*(n))+1;
    }
    return 0;
}

 

2 odpowiedzi

+3 głosów
odpowiedź 8 maja 2017 przez mokrowski Mędrzec (155,460 p.)
wybrane 8 maja 2017 przez chucksqll
 
Najlepsza

W funkcjach rekurencyjnych powinieneś zawsze zastanowić się co będzie warunkiem stopu. W przypadku podanym w zadaniu jest to osiągnięcie przez zmienną wartości 1. Jak ta wartość zostanie osiągnięta, należy zwrócić wartość licznika.

Na razie pseudokod:

unisgned collatz(unsigned s, ...) {
    if( s == 1 ) {
        return counter;
    }
}

Jak widać na razie nie ma żadnej informacji skąd wziął się counter i co ma się z nim dziać. Jeśli chcesz by był inkrementowany w każdym wywołaniu, możesz go przekazać jako kopię w 2 argumencie. Aby było wygodniej, ten argument ustaw domyślnie na 0:

unisgned collatz(unsigned s, unsigned counter = 0) {
    if( s == 1 ) {
        return counter;
    }
}

Oczywiście funkcja dalej jest nieprawidłowa bo nie posiada wywołania rekurencyjnego oraz będzie zwracała (jakie zwracała? przecież dla s != 1 nie ma nic zwracanego !) nieprawidłowe wartości.

Należy więc dodać wywołania rekurencyjne. Za każdym razem wywołanie będzie wymagało inkrementowania licznika wywołań (stąd pojawi się ++counter w następnym wywołaniu). Pojawi się także test "jak liczyć gdy s jest parzyste" oraz "jak liczyć gdy nie jest parzyste". Nie chcę Cię pozbawiać przyjemności rozwiązania, więc podam tylko szkielet:

unisgned collatz(unsigned s, unsigned counter = 0) {
    if( s == 1 ) {
        return counter;
    }
    if( s jest nieparzyste) {
        return collatz(oblicznie s dla wywołania nieparzystego, ++counter);
    } else { // wiadomo że jest parzyste.. 
        return collatz(oblicznie s dla wywołania parzystego, ++counter);
    }
    // Tu program nigdy nie dojdzie bo liczba będzie parzysta lub nie :-)
}

Pozostanie dopisanie tylko funkcji main(). Taka rekurencja w której wszystkie argumenty wysyłasz przez wywołanie i "sam return jest wywołaniem funkcji z argumentami", będzie potraktowana przez dobry kompilator jako tzw. rekurencja ogonowa (https://pl.wikipedia.org/wiki/Rekurencja_ogonowa ). Taka rekurencja nie spowoduje przeciążenia stosu wywołań. Wprawdzie standard C++ tego nie wymaga, ale tak to implementują szanujące się kompilatory :-)

Poniżej umieszczę już "podrasowaną wersję". Zerkaj tylko jeśli już rozwiążesz samodzielnie żebyś wiedział skąd biorą się inaczej zapisane wywołania :-)

#include <iostream>

unsigned collatz(unsigned s, unsigned count = 0) {
    return s == 1 ? count : collatz(s % 2 ? 3 * s + 1: s / 2, ++count);
}

int main() {
    unsigned s;
    unsigned n;
    std::cin >> n;
    while(n--> 0) {
        std::cin >> s;
        std::cout << collatz(s) << '\n';
    }
}

 

0 głosów
odpowiedź 8 maja 2017 przez Dexterim Dyskutant (8,370 p.)

Tu raczej powinieneś poczytać coś o funkcji rekurencyjnej.

Nie możesz zrobić tak jak napisałeś ponieważ nie masz przypadku podstawowego i de facto cały czas w nieskończoność wywołujesz funkcje x(n).

Myślę, że chyba chciałeś napisać tak:

int x(n){
   if( n == 1)
        return n;
    else
       return x(n-1);

}

 

komentarz 8 maja 2017 przez Munvik Dyskutant (9,350 p.)

Tu raczej chodzi o operandy. 

x(n+1)=x(n)/2;

Lewy operand to funkcja, czyli coś przypisujesz do funkcji. Co to miałoby niby znaczyć ?

komentarz 8 maja 2017 przez chucksqll Stary wyjadacz (12,930 p.)
Chciałem przez to określić jak określony jest wyraz ciągu, parzysty i nieparzysty. Jak miałbym to inaczej zrobić przy funkcji?
komentarz 8 maja 2017 przez Dexterim Dyskutant (8,370 p.)
@Munvik tu też masz racje, napisał o problemie z funkcja więc zajrzałem tam na szybko i to co powiedziałem jest również prawdą
komentarz 8 maja 2017 przez chucksqll Stary wyjadacz (12,930 p.)

Rzecz w tym, że pisząc ten kod właśnie chciałbym lepiej zrozumieć rekurencje, z zadaniem ze spoja "Problem collatza".

Poniżej przyblizyłem mój tok myślenia

int x(int n)
{
    if(x(n)==1)// w tym miejscu chcialem sprawdzic czy n-ty wyraz ciagu rowna sie 1 
        return n;
 
    else
        return x(n+1);// jesli nie rozpratruje kolejny wyraz
 
}

/////////////////////////

if(x(n)%2==0)
    {
        x(n+1)=x(n)/2;//dla parzystego parzystego wyrazu ciagu kolejny wyraz okreslam wlasnie takim wzorem
    }
    if(x(n)%2!=0)
    {
        x(n+1)=(3*(n))+1;// to samo dla nieparzystego
    }

 

komentarz 8 maja 2017 przez Dexterim Dyskutant (8,370 p.)

w miejscu 


    if(x(n)==1)

nie sprawdzasz czy wyraz ciągu równa się jeden a wywłujesz funkcje x.

Myślę, że lepiej zacząć od podstaw ponieważ mylisz wywołanie funkcji z odwołaniem sie do tablicy

Podobne pytania

0 głosów
2 odpowiedzi 663 wizyt
pytanie zadane 10 kwietnia 2016 w C i C++ przez danior Początkujący (330 p.)
+4 głosów
2 odpowiedzi 192 wizyt
0 głosów
2 odpowiedzi 148 wizyt
pytanie zadane 8 października 2018 w Java przez asgaard Obywatel (1,300 p.)

92,551 zapytań

141,393 odpowiedzi

319,523 komentarzy

61,936 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...