Strona 1 z 1

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 17:44
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 ?

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 18:12
autor: Ser Cubus
if(n==0 and n==1)

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

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 18:16
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)

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 18:24
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++.

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 18:54
autor: Majka99
\(\displaystyle{ C_{n+1} = C_0C_n + C_1C_{n-1} + . . . + C_{n-1}C_1 + C_nC_0}\)

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 20:20
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.

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 20:28
autor: Afish
No to masz źle pętlę oraz warunek stopu, jak już Ser Cubus wspomniał.

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 21:38
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);
}

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 21:46
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...

[C++] Obliczanie wzoru Catalana

: 23 sie 2013, o 22:14
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.

[C++] Obliczanie wzoru Catalana

: 24 sie 2013, o 13:23
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++.

[C++] Obliczanie wzoru Catalana

: 24 sie 2013, o 14:34
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.

[C++] Obliczanie wzoru Catalana

: 24 sie 2013, o 16:40
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.