[C++] Obliczanie wzoru Catalana

Majka99
Użytkownik
Użytkownik
Posty: 152
Rejestracja: 20 paź 2012, o 12:54
Płeć: Kobieta
Lokalizacja: zgierz
Podziękował: 15 razy

[C++] Obliczanie wzoru Catalana

Post autor: Majka99 »

Kod: Zaznacz cały

#include <iostream>

using namespace std;

int catalan(int n)
{  

	if(n==0 and n==1)
	return 1;
	for(int i=0;i<=n;i++)

	
	return catalan(i)*catalan(n-1)+catalan(n);
}




int main(int argc, char** argv) {
	
	int n;
	cin>>n;
	cout<<catalan(n)<<endl;
	return 0;
}
Mam cos takiego,lecz nie dziala,gdzie blad ?
Ostatnio zmieniony 23 sie 2013, o 18:14 przez Afish, łącznie zmieniany 1 raz.
Powód: Staraj się lepiej dobierać nazwy tematów, tak by wskazywały o czym jest treść zadania.
Ser Cubus
Użytkownik
Użytkownik
Posty: 1406
Rejestracja: 6 maja 2012, o 22:46
Płeć: Mężczyzna
Lokalizacja: Polska
Podziękował: 107 razy
Pomógł: 145 razy

[C++] Obliczanie wzoru Catalana

Post autor: Ser Cubus »

if(n==0 and n==1)

nie miało być if(n==0 or n==1) ?
bartek118
Użytkownik
Użytkownik
Posty: 5974
Rejestracja: 28 lut 2010, o 19:45
Płeć: Mężczyzna
Lokalizacja: Toruń
Podziękował: 15 razy
Pomógł: 1251 razy

[C++] Obliczanie wzoru Catalana

Post autor: bartek118 »

Ser Cubus pisze:if(n==0 and n==1)

nie miało być if(n==0 or n==1) ?
Raczej

Kod: Zaznacz cały

if(n==0 || n==1)
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C++] Obliczanie wzoru Catalana

Post autor: Afish »

W pętli kręcisz się tylko raz i od razu zwracasz wynik, raczej nie o to chodziło. Podaj dokładnie wzór, według którego chcesz obliczać, bo na wiki jest inny.

bartek118, literały słowne są w C++.
Majka99
Użytkownik
Użytkownik
Posty: 152
Rejestracja: 20 paź 2012, o 12:54
Płeć: Kobieta
Lokalizacja: zgierz
Podziękował: 15 razy

[C++] Obliczanie wzoru Catalana

Post autor: Majka99 »

\(\displaystyle{ C_{n+1} = C_0C_n + C_1C_{n-1} + . . . + C_{n-1}C_1 + C_nC_0}\)
Ostatnio zmieniony 23 sie 2013, o 20:27 przez Afish, łącznie zmieniany 1 raz.
Powód: Poprawa wiadomości.
bartek118
Użytkownik
Użytkownik
Posty: 5974
Rejestracja: 28 lut 2010, o 19:45
Płeć: Mężczyzna
Lokalizacja: Toruń
Podziękował: 15 razy
Pomógł: 1251 razy

[C++] Obliczanie wzoru Catalana

Post autor: bartek118 »

Myślę, że jeśli z tego typu wzoru liczysz, to najlepiej tablicować wynik (chyba, że \(\displaystyle{ n}\) ma być jakieś bardzo duże, to wtedy jeśli masz ograniczenie na pamięć to warto pomyśleć nad czymś sprytniejszym. Rekurencja napisana tak ot wprost będzie wysoce nieefektywna.
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C++] Obliczanie wzoru Catalana

Post autor: Afish »

No to masz źle pętlę oraz warunek stopu, jak już Ser Cubus wspomniał.
zeus_156
Użytkownik
Użytkownik
Posty: 36
Rejestracja: 9 sie 2013, o 15:16
Płeć: Mężczyzna
Lokalizacja: KRK
Pomógł: 7 razy

[C++] Obliczanie wzoru Catalana

Post autor: zeus_156 »

Wzór który podałaś jest na \(\displaystyle{ C_{n+1}}\)
Zapisując to dla \(\displaystyle{ C_{n}}\) (bo właśnie tak wykorzystujesz w programie) otrzymujemy:
\(\displaystyle{ C_{n}=\sum_{i=0}^{n-1} C_{i} \cdot C_{n-1-i}}\)
to funkcja powinna wyglądać tak:

Kod: Zaznacz cały

int catalan(int n)
{ 
   int output = 0;
   if(n <= 1) return 1;
   for(int i=0; i<=n-1; i++) 
   {
      output += catalan(i) * catalan(n-1-i);
   }
   return output;
}
Czas wykonania jest oczywiście obłędnie długi. Przydało by się zastosować zbieranie już wyliczonych danych w tablicy lub skorzystać z innego wzoru
np: \(\displaystyle{ C_{n}=\frac{2(2n-1)}{n+1} C_{n-1}}\) to funkcja powinna wyglądać tak:

Kod: Zaznacz cały

int catalan(int n)
{ 
   if(n <= 1) return 1;
   return catalan(n-1) * 2 * (2 * n - 1) / (n + 1);
}
Ser Cubus
Użytkownik
Użytkownik
Posty: 1406
Rejestracja: 6 maja 2012, o 22:46
Płeć: Mężczyzna
Lokalizacja: Polska
Podziękował: 107 razy
Pomógł: 145 razy

[C++] Obliczanie wzoru Catalana

Post autor: Ser Cubus »

bartek118 pisze:
Ser Cubus pisze:if(n==0 and n==1)

nie miało być if(n==0 or n==1) ?
Raczej

Kod: Zaznacz cały

if(n==0 || n==1)
przecież obie formy są poprawne...
zeus_156
Użytkownik
Użytkownik
Posty: 36
Rejestracja: 9 sie 2013, o 15:16
Płeć: Mężczyzna
Lokalizacja: KRK
Pomógł: 7 razy

[C++] Obliczanie wzoru Catalana

Post autor: zeus_156 »

Dla większych wartości (dla pierwszego wzoru \(\displaystyle{ n>=20}\), dla drugiego wzoru \(\displaystyle{ n>=17}\)) dobrze by zastosować zmienne 64 bitowe.
Wtedy będzie to wyglądać tak:

Kod: Zaznacz cały

unsigned long long catalan(int n)
{ 
   unsigned long long output = 0;
   if(n <= 1) return 1;
   for(int i=0; i<=n-1; i++) 
   {
      output += catalan(i) * catalan(n-1-i);
   }
   return output;
}
lub:

Kod: Zaznacz cały

unsigned long long catalan(int n)
{ 
   if(n <= 1) return 1;
   return catalan(n-1) * 2 * (2 * n - 1) / (n + 1);
}
Działanie kodu sprawdziłem na Visual Studio 2008.
Majka99
Użytkownik
Użytkownik
Posty: 152
Rejestracja: 20 paź 2012, o 12:54
Płeć: Kobieta
Lokalizacja: zgierz
Podziękował: 15 razy

[C++] Obliczanie wzoru Catalana

Post autor: Majka99 »

zeus_156 pisze:Wzór który podałaś jest na \(\displaystyle{ C_{n+1}}\)
Zapisując to dla \(\displaystyle{ C_{n}}\) (bo właśnie tak wykorzystujesz w programie) otrzymujemy:
\(\displaystyle{ C_{n}=\sum_{i=0}^{n-1} C_{i} \cdot C_{n-1-i}}\)
to funkcja powinna wyglądać tak:

Kod: Zaznacz cały

int catalan(int n)
{ 
   int output = 0;
   if(n <= 1) return 1;
   for(int i=0; i<=n-1; i++) 
   {
      output += catalan(i) * catalan(n-1-i);
   }
   return output;
}
Czas wykonania jest oczywiście obłędnie długi. Przydało by się zastosować zbieranie już wyliczonych danych w tablicy lub skorzystać z innego wzoru
np: \(\displaystyle{ C_{n}=\frac{2(2n-1)}{n+1} C_{n-1}}\) to funkcja powinna wyglądać tak:

Kod: Zaznacz cały

int catalan(int n)
{ 
   if(n <= 1) return 1;
   return catalan(n-1) * 2 * (2 * n - 1) / (n + 1);
}
Wszystko rozumiem oprocz polecenia output.Czy jest to jak tablica czy polecenie ?Pierwszy raz sie z nim spotykam w jezyku c++.
bartek118
Użytkownik
Użytkownik
Posty: 5974
Rejestracja: 28 lut 2010, o 19:45
Płeć: Mężczyzna
Lokalizacja: Toruń
Podziękował: 15 razy
Pomógł: 1251 razy

[C++] Obliczanie wzoru Catalana

Post autor: bartek118 »

Majka99 pisze:
zeus_156 pisze:Wzór który podałaś jest na \(\displaystyle{ C_{n+1}}\)
Zapisując to dla \(\displaystyle{ C_{n}}\) (bo właśnie tak wykorzystujesz w programie) otrzymujemy:
\(\displaystyle{ C_{n}=\sum_{i=0}^{n-1} C_{i} \cdot C_{n-1-i}}\)
to funkcja powinna wyglądać tak:

Kod: Zaznacz cały

int catalan(int n)
{ 
   int output = 0;
   if(n <= 1) return 1;
   for(int i=0; i<=n-1; i++) 
   {
      output += catalan(i) * catalan(n-1-i);
   }
   return output;
}
Czas wykonania jest oczywiście obłędnie długi. Przydało by się zastosować zbieranie już wyliczonych danych w tablicy lub skorzystać z innego wzoru
np: \(\displaystyle{ C_{n}=\frac{2(2n-1)}{n+1} C_{n-1}}\) to funkcja powinna wyglądać tak:

Kod: Zaznacz cały

int catalan(int n)
{ 
   if(n <= 1) return 1;
   return catalan(n-1) * 2 * (2 * n - 1) / (n + 1);
}
Wszystko rozumiem oprocz polecenia output.Czy jest to jak tablica czy polecenie ?Pierwszy raz sie z nim spotykam w jezyku c++.
output w tym przypadku to po prostu nazwa zmiennej - przechowuje ona wynik sumowania w trakcie liczenia.
zeus_156
Użytkownik
Użytkownik
Posty: 36
Rejestracja: 9 sie 2013, o 15:16
Płeć: Mężczyzna
Lokalizacja: KRK
Pomógł: 7 razy

[C++] Obliczanie wzoru Catalana

Post autor: zeus_156 »

Nazwę zmiennej tymczasowej możesz sobie dowolnie wybrać np: x

Kod: Zaznacz cały

int catalan(int n)
{ 
   int x = 0;
   if(n <= 1) return 1;
   for(int i=0; i<=n-1; i++) 
   {
      x += catalan(i) * catalan(n-1-i);
   }
   return x;
}
Jeżeli chcesz zbierać w tablicy wyniki obliczeń pośrednich to program będzie wyglądał tak:

Kod: Zaznacz cały

#include <iostream>

using namespace std;

//Przy 32 bitowym typie dany i tak bedzie tylko 20 elementow  
int tablicaWynikow[50] = {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 

int catalan(int n)
{ 
   int x = 0; //Inicjacja zmiennej tymczasowej
   if(n>=0 && n<50)  //Zabezpieczenie aby nie czytac pamieci poza tablica
   {
      if(tablicaWynikow[n] > 0) return tablicaWynikow[n]; //Wynik byl juz raz wyliczony, wiec go uzyj
      for(int i=0; i<=n-1; i++) 
      {
         x += catalan(i) * catalan(n-1-i);
      }
      //Jak nastapi przepelnienie zmiennej to wynik dodawania bedzie ujemny
      if(x < 1) throw "Przekroczono zakres wartosci jaki moze zawierac typ int!";
      tablicaWynikow[n] = x;  //Zapisz wynik dla aktualnej n-tej warosci Catalana
   }
   return x;
}

int main(int argc, char** argv)
{
   int n;
   cin>>n;
   try {
      cout<<catalan(n)<<endl;
   }
   catch(char * str) {
      cout << "Exception raised: " << str << '\n';
   }
   return 0;
}
Sama oceń jak bardzo tablicowanie wyników pośrednich przyspieszyło obliczenia.
ODPOWIEDZ