1. 程式人生 > >【 OJ 】 HDOJ1023 18年11月08日17:11 [ 22 ]

【 OJ 】 HDOJ1023 18年11月08日17:11 [ 22 ]

遲來的正義.....

ummmm,此題不會,全排列爆炸的可能

對於卡特蘭數並沒有理解....

f(n)=f(0)*f(n-1)+f(1)*f(n-2)......f(n-1)*f(0);

---------------------------------------------------------

首先,我們設f(n)=序列個數為n的出棧序列種數。(我們假定,最後出棧的元素為k,顯然,k取不同值時的情況是相互獨立的,也就是求出每種k最後出棧的情況數後可用加法原則,由於k最後出棧,因此,在k入棧之前,比k小的值均出棧,此處情況有f(k-1)種,而之後比k大的值入棧,且都在k之前出棧,因此有f(n-k)種方式,由於比k小和比k大的值入棧出棧情況是相互獨立的,此處可用乘法原則,f(n-k)*f(k-1)種,求和便是Catalan遞迴式。

這題特麼....看錯了,整個思路基於假設【最後出棧的元素為k】,我看成了假設第一個出棧元素是K,那麼f(n-k)可以理解,前面的怎麼也想不出來是怎麼回事為什會是f(k-1)........

此題由於前面的可以推出是卡特蘭數,做時候要用

另類遞推式:

h(n)=h(n-1)*(4*n-2)/(n+1);

本題基本就是得到這個公式然後大數陣列的乘法和除法運算即可.....

有點難受................想到爆炸也想不到的.................

如果說得到了上述的推式,那麼一切都好辦了,做的時候按部就班的算即可,先算(4*n-2)/(n+1) 然後在和h(n-1)做乘法,咋看感覺很好,少了一次大數除法,我開始就是這麼想的,但是當n=3時候 (4*n-2)/(n+1)=2.5..... 2.5和h(n-1)做乘法會丟失資料,是個坑【可能是我並不會小數點和陣列做乘法有關,如果分數可以和陣列的數做乘法那麼這個方法還是比較好的】

AC程式碼如下:

# include<iostream>
using namespace std;
int C[200][200];//C[n][0]表示n的卡特蘭數的長度,儲存是反向的,C[n][1]表示個位數 
void Catalan(void) {
	C[0][0] = C[0][1] = 1;
	C[1][0] = C[1][1] = 1;
	int carry,digit,sum;
	double t;
	for (int i = 2; i < 101; i++)//去碰一下 i=2 的坑
	{
		t = (4 * i - 2);
		carry = sum = 0;
		//只需要求 h(i-1)並分為儲存
		for (int j = 1; j <= C[i - 1][0]; ++j)//C[i-1][0] 為 h(i-1)的長度
		{
			sum = C[i - 1][j] * t + carry;
			C[i][j] = sum % 10;
			carry = sum / 10;
		}
		digit = C[i - 1][0];
		while (carry) {//此時位數開始在原基礎上增加
			digit++;
			C[i][digit] = carry % 10;
			carry /= 10;
		}
		//此時已經求出了 h(n-1)*(4*n-2)  接著 /(n+1); 
		for (int j = digit; j > 0; j--) {
			sum = C[i][j] + carry * 10;
			C[i][j] = sum / (i + 1);
			carry = sum % (i + 1);
		}
		while (!C[i][digit]) {
			digit--;
		}
		C[i][0] = digit;
	}
}
int main(void) {
	int N;//火車數
	Catalan();
	while (cin >> N) {//非整形退出
		if (N <= 0)
			return 0;
		for (int i = C[N][0]; i > 0; i--) {
			cout << C[N][i];
		}
		cout << endl;
	}
	system("pause");
	return 0;
}