ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

紫书学习 10.数学概念与方法--递推和计数问题

2022-07-22 11:40:06  阅读:186  来源: 互联网

标签:10 紫书 方案 -- 路径 int 非降 2n 递推


紫书给出了三个非常经典的递推模型。

汉诺塔问题

要求将A杆子的圆盘全部移到B杆子,并保持同样的叠放顺序。

要求:

  1. 每次只能移动顶部的盘子。
  2. 圆盘可以插在任一杆子上。
  3. 任何时刻都不能把小盘放在大盘上面。

求移动需要的步数。

解法:

假设移动n个盘子的方案是\(f(n)\),要把n个盘子移到B柱子,可以先把n-1个较小的盘子移到C柱子,再把最大的盘子移到B柱子,最后再把C柱子上的n-1个盘子移到B上。得出递推式:

\[f(n)=2*f(n-1)+1 \]

基于递推式观察和归纳得到更简洁的写法:

\[f(n)=2^n-1 \]

汉诺塔问题是经典的递归入门题,分析中的“先把n-1个较小的盘子移动到C柱子上”就运用了递归思想。

Fibonacci数列

爬台阶问题

大意:要爬上n级台阶,每次可以爬一级或者两级,问爬上n级台阶有多少种方案。

解答:假设爬上i级台阶有\(f(i)\)种方案数。显然\(f(0)=1\),\(f(1)=1\),\(f(2)=2\)。要爬上三级台阶,可以先走一步到一级再一次爬两级,也可以先爬两级再一次爬一级,所以\(f(3)=f(1)+f(2)\)。进一步归纳得递推关系式:

\[f(i)=f(i-1)+f(i-2) \]

和斐波那契数列递推式一模一样。

兔子问题

大意:现在有雌雄一对新兔子。每对兔子从第二个月开始每月产雌雄一对新兔子。问n个月之后有多少对兔子。

解答:设第i个月有兔子\(f(i)\),可知\(f(1)=f(2)=1\),\(f(3)=2\)。对任意\(f(i)\),第\(i-1\)个月有\(f(i-1)\)对兔子,第\(i-1\)个月的兔子又生了\(f(i-2)\)对兔子,所以有:

\[f(i)=f(i-1)+f(i-2) \]

铺地砖问题

大意:有一两行n列的地面,现有1x22x1两种地砖,问铺满地面有多少种方案。

解答:假设铺满n列的地面有\(f(n)\)种方案,一开始可以先摆一块竖的地砖,剩下部分的铺设方案就是\(f(n-1)\),也可以先摆两块横的地砖,剩下的铺设方案就是 \(f(n-2)\),所以也有:

\[f(n)=f(n-1)+f(n-2) \]

另一种解答:可以假设在第i列摆放了竖的地砖,于是两边的摆放方案分别是\(f(i-1),f(n-i)\),再枚举所有摆了竖砖的列,就有:

\[f(n)=\sum f(i-1)*f(n-i),1\le i\le n \]

但是这种方法是有很多重复的,因为\(f(i-1)\)肯定也会包含摆放了竖砖的方案。

尝试改进这种方法,可以假设在第i列摆放了第一块竖的地砖,这样就除去了冗余了。

那么递推式如何?分析到如果第i列摆放了第一块竖砖,那么前\(i-1\)列就都要摆放横砖,有1种方案,其中\(i-1\)必须是偶数,否则就不存在这种方案;后面列的摆放方案数就是\(f(n-i)\)。

所以可以得到最后的递推式:

\[f(n)=f(n-1)+f(n-3)+....+f(2)+f(0),n为奇数 \]

\[f(n)=f(n-1)+f(n-3)+.....+f(1)+1,n为偶数 \]

n为偶数时,最后加上的1就是没有竖砖的方案。

最后发现这个数列和斐波那契数列的值完全一样。

应用:Fibonacci数列取模的循环节

如果对斐波那契数列取模,只要项数足够,就一定会出现循环节。具体见题目。

Colossal Fibonacci Numbers! - UVA 11582 - Virtual Judge (vjudge.net)

题目大意:假设斐波那契数列的值为\(f(i)\),给定a,b和n,求\(f(a^b)\%n\),其中\(0 \leq a,b <2^{64}\),\(1\le n\le 1000\)。

解答:题目的数据范围非常大,但是n比较小。注意到,如果数列有相邻两项取模后和是以前出现过的数,那么根据Fibonacci递推式:

\[f(i)=f(i-1)+f(i-2) \]

这相邻两项之后的项就会开始循环。

现在的问题有两个:

  1. 循环节有多长,怎么找?

    每一项取余之后的范围是\([0,n)\),因此每相邻两项的所有排列有\(n^2\)种,根据抽屉原理,只要枚举到第\(n^2+1\)项,就一定会出现相同的排列,即出现了循环节。枚举到\(n^2\)的时间是可以接受的。

  2. 一定从首项\(f(0)=f(1)=1\)开始循环吗

    实际上只要证明\((f(i-2)+f(i-1))\%m=f(i)\),在%m的条件下有唯一解,就能证明只要有\(f(i),f(i-1)\)发生重复,就可以推到\(f(i-1),f(i-2)\)发生重复,一直推回去就知道首项重复。

    这里我不太理解其中的奥秘,希望有大佬能证。。。

CODE:

const int N=1005;
typedef unsigned long long ull;
ull a,b;
int n;
int T;
int f[N*N];

ull qm(ull a,ull k,int p){
	ull tmp=1;
	while(k){
		if(k&1)tmp=tmp*a%p;
		k>>=1;
		a=a*a%p;
	}
	return tmp;
}

int main(){
	scanf("%d",&T);
	f[0]=0;f[1]=1;
	while(T--){
		cin>>a>>b>>n;
		if(n==1 || a==0){ cout<<0<<endl; continue;}
		int loop;
		for(int i=2;i<=n*n;i++){//枚举循环节
			f[i]=(f[i-1]+f[i-2])%n;
			if(f[i]==f[1] && f[i-1]==f[0]){ loop=i-1; break;}
		}
		cout<<f[qm(a%loop,b,loop)]<<endl;
	}
	return 0;
}

应用:铺地砖另一种解法的应用

这种通过限定第一个位置来去除枚举重复的方法非常好用,比如这题。

Critical Mass - UVA 580 - Virtual Judge (vjudge.net)

题目大意:有无数个U和L字符,要求把n个字符组成一个字符串,并且至少有3个U放在一起,问有多少种放法。

解答:类似之前的分析方法,可以假设第一次连续的UUU出现在字符串的第\(i,i+1,i+2\)位上,那么第\(i+2\)位后可以随意摆放,方案就是\(2^{n-i-2}\)种;第i位前面必须保证没有连续3个的U,假设方案为\(g\),那么\(g(i-1)=2^{i-1}-f(i-1)\)。

但是这种方法同样有冗余,因为\(g(i-1)\)中一定会有\(i-1\)位出现U的情况,最后就和“第一次连续的UUU出现在字符串”出现在i矛盾,因此还需要把\(i-1\)位定成L,那么左边就是\(g(i-2)\)。

还有一个小细节就是当第一组UUU出现在首位的时候,前面没法放L,需要另外计算:方案数是\(2^{n-3}\)

CODE:

typedef long long ll;
const int N=35;
int n;
ll f[N],g[N];
int p[N];

int main(){
	f[1]=f[2]=0; f[3]=1;
	g[0]=1; g[1]=2; g[2]=4;
	p[0]=1;
	for(int i=1;i<=N-5;i++)p[i]=2*p[i-1];//算出2的幂
	for(int n=4;n<=N-5;n++){
		g[n-1]=p[n-1]-f[n-1];
		f[n]=p[n-3];
		for(int i=2;i<=n-2;i++){
			f[n]+=g[i-2]*p[n-i-2];
		}
	}
	
	while(scanf("%d",&n) && n){
		cout<<f[n]<<endl;
	}
	return 0;
}

Catalan数

卡特兰数常用表达式

涉及对角线的非降路径

非降路径

从\((0,0)\)开始走到\((m,n)\),只能向右或者向上走,有多少种走法?

一共要走\(m+n\)步,然后其中有m步是向右走的,答案就是\(C_{m+n}^{m}\)种方案。

Catalan数和非降路径更多是通过组合数\(C\)联系起来的。

不接触非降路径:

考虑从\((0,0)\)走到\((n,n)\)的,不接触对角线\(x=y\)的非降路径。直接根据对称性,只考虑下半部分,由于不经过\(x=y\),所以原路径和从\((1,0)\)走到\((n,n-1)\)的路径等价,因此所有非降路径的数目有\(C_{2n-2}^{n-1}\)种。对于任意一条接触到了对角线的路径(如下图),都可以把前缀一段包括穿过的部分做关于\(x=y\)的对称,最后变成起点为\((0,1)\),终点为\((n,n-1)\)的路径。因此下半部分不接触\(x=y\)的非降路径数目就是\(C_{2n-2}^{n-1}-C_{2n-2}^{n}\)

不穿过非降路径:

类似地可以对穿过对角线的路径进行对称转化,从而求出其数量。每条穿过对角线路径都一定会经过下图中的黑色虚对角线,我们把后缀一段包括穿过\(y=x\)对角线的部分关于黑色虚线做对称,最后注意到穿过对角线的路径就等价于从 \((0,0)\)走到\((n-1,n+1)\)的路径。因此下半部分不穿过非降路径的数目是\(C_{2n}^{n}-C_{2n}^{n-1}=\frac{C_{2n}^{n}}{n+1}\)

非降路径的应用

以下计数问题都可以转化成非降路径问题:

  1. 有\(2n\)个人排成一行进入剧场。入场费 5 元。其中只有\(n\)个人有一张 5 元钞票,另外\(n\)人只有 10 元钞票,剧院无其它钞票,问有多少种方法使得只要有 10 元的人买票,售票处就有 5 元的钞票找零?

    解法:建立坐标轴,横轴上+1表示花5元,纵轴上+1表示花10元,最后一种合法方案就是从\((0,0)\)到\((n,n)\)的一条不穿过非降路径。

  2. 一个栈(无穷大)的进栈序列为\(1,2,3,4,5,...,n\),有多少个不同的出栈序列?

    解法:每次可以考虑出栈 或 进栈,但是到目 前为止进栈的总次数必须大于等于出栈的总次数。建立坐标系,把进栈看成横轴+1,出栈看成纵轴+1,出进栈的次数总共是\(2n\),所以就转化成了不穿过非降路径问题。

划分

以下划分问题更贴近的是Catalan的递推形式

  1. 对角线不相交的情况下,将一个凸\(n\)边形区域分成三角形区域的方法数?

    对每个顶点从1到n编号,以边\((1,n)\)为三角形的一边,枚举三角形的另一个点,假设三角形的另一个点在\(k\)位置,于是n边形就被分成了\(k\)边形和\(n-k+1\)边形,于是可以写出式子:

    \[f(n)=f(2)f(n-1)+f(3)f(n-2).....+f(n-1)(2) \]

  2. 在圆上选择\(2n\)个点,将这些点成对连接起来使得所得到的\(n\)条线段不相交的方法数?

    可以类似1的作划分,从1点开始,枚举连接线段\((1,k)\)

  3. \(n\)个结点可构造多少个不同的二叉树?

    可以类似中序遍历的思想,枚举根节点,划分出左子树和右子树。

标签:10,紫书,方案,--,路径,int,非降,2n,递推
来源: https://www.cnblogs.com/tshaaa/p/16505138.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有