洛谷官方题单【算法1-4】递推与递归

1.p1255数楼梯
解题思路:斐波那契数列+高精度加法
一定要用高精度加法,否则只有50分左右

#include 
using namespace std;
int f[5001][5000]={0};//数组开太大内存会爆掉
void jf(int k){//高精度加法,先加再进位
	for(int i=0;i<=4999;i++){
		f[k][i]=f[k-1][i]+f[k-2][i];
	}
	for(int i=0;i<=4999;i++){
		f[k][i+1]+=f[k][i]/10;
		f[k][i]=f[k][i]%10;
	}
}
int main(){
	f[1][0]=1;
	f[2][0]=2;
	int n,flag=0;
	cin >> n;
	for(int i=3;i<=n;i++){
		jf(i);
	}//f[n]=f[n-1]+f[n-2]
	for(int i=4999;i>=0;i--){
		if(f[n][i]!=0){
			flag=1;
		}
		if(flag){
			cout << f[n][i];
		}
	}
	if(flag==0){
		cout << 0;
	}
	return 0;
} 

2.P1002 [NOIP2002 普及组] 过河卒
解题思路:动态规划+注意边界
输出有多少条路的题是典型的动态规划题

#include 
#include 
using namespace std;
int m[21][21]={0};
long long f[21][21]={0};
struct node{
	int x;
	int y;
};
int p[2][8]={{-2,-1,1,2,2,1,-1,-2},{1,2,2,1,-1,-2,-2,-1}};
int main(){
	node ma,b;
	cin >> b.x >> b.y >> ma.x >> ma.y;
	m[ma.x][ma.y]=1;
	for(int i=0;i<8;i++){
		if(ma.x+p[0][i]>=0 && ma.x+p[0][i]<=20 && ma.y+p[1][i]>=0 && ma.y+p[1][i]<=20){
			m[ma.x+p[0][i]][ma.y+p[1][i]]=1;
		}
	}
	if(m[0][1]==0){
		f[0][1]=1;
	}
	if(m[1][0]==0){
		f[1][0]=1;
	}//以上两步为初始化步骤
	for(int i=0;i<=b.x;i++){
		for(int j=0;j<=b.y;j++){
			if(m[i][j]==1 || i==0&&j==1 || i==1&&j==0){
				continue;
			}//如果这个点不能走或者是已经初始化的点,不能进行更改
			if(i-1>=0 && j-1>=0){
				f[i][j]=f[i-1][j]+f[i][j-1];//如果向前两个点都在图内则都加上
			}else if(i-1>=0 && j-1<0){
				f[i][j]=f[i-1][j];
			}else if(i-1<0 && j-1>=0){
				f[i][j]=f[i][j-1];
			}
		}
	}
	cout << f[b.x][b.y];//输出有多少条路
	return 0;
}

3.P1044 [NOIP2003 普及组] 栈
解题思路:转换为卡特兰数
对于序列里的每一个数都有可能是最后一个出栈的,设这个数为X,对于小于X的X-1个数出栈顺序有F[X-1]种,对于大于X的N-X-1个数出栈顺序有F[N-X-1]种,则对于X可以组成的出栈序列有F[X-1]*F[N-X-1]种,遍历X从1到N,就构成了卡特兰数

#include 
using namespace std;
long long f[19]={0},sum=0;
int main(){
	int n;
	cin >> n;
	f[0]=1;
	f[1]=1;
	for(int k=2;k<=n;k++){
		for(int i=0;i<=k-1;i++){
			f[k]+=f[i]*f[k-i-1];
		}
	}
	cout << f[n];
	return 0;
}

4.P1028 [NOIP2001 普及组] 数的计算
解题思路:循环模拟递归

#include 
using namespace std;
int f[1001];
int main(){
	int n,j;
	cin >> n;
	f[0]=0;
	f[1]=1;
	for(int i=2;i<=n;i++){//给出从2到n的每一个数的可能
		//递推公式为f[n]=1+f[(n/2)-1]+f[(n/2)-2]+...f[1]
		//即n前面能加N/2,N/2-1,...,1其它不行
		f[i]=1;
		j=i/2;
		while(j>0){
			f[i]+=f[j];
			j--;
		}
	}
	cout << f[n];
	return 0;
}

5.P1010 [NOIP1998 普及组] 幂次方
解题思路:递归
用于递归的函数每次输入进去的是一个需要转换成二进制表示的数,所以我们先将其转换为二进制,并且用一个x[16]数组存储。
其次我们对二进制的每一位进行输出,首先需要肯定的是只有该二进制位为1的时候才需要输出,其次我们只直接输出1,2,4的二进制表示,其余位需要进一步转换,所以对于i!=0,1,2的位我们先用2将其包住,再进行递归。
需要注意的是,对于输出的i不是最后一个需要输出的位时,我们要在他们后面加一个+

#include 
using namespace std;
int sc(int n){
	int x[16],min=-1,i=0;
	while(n>0){
		x[i]=n%2;
		n=n/2;
		if(min==-1 && x[i]==1){
			min=i;
		}
		i++;
	}
	i--;
	while(i>=0){
		if(x[i]!=0){
			if(i==0 || i==1 || i==2){
				if(i==0){
					cout << "2(0)";
				}else if(i==1){
					cout << "2";
				}else if(i==2){
					cout << "2(2)";
				}
			}else{
				cout << "2(";
				sc(i);
				cout << ")";	
			}
			if(i!=min){
					cout << "+";
			}
		}
		i--;
	}
}
int main(){
	int n;
	cin >> n;
	sc(n);
	return 0;
}

未完待续…

你可能感兴趣的:(洛谷官方题单算法1-4)