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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/QingCoffe/article/details/83685719

迟来的正义.....

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;
}

猜你喜欢

转载自blog.csdn.net/QingCoffe/article/details/83685719