一本通 2.4.1 递归算法

1315:【例4.5】集合的划分

【题目描述】

【题目分析】

 【代码实现】

#include<bits/stdc++.h>

using namespace std;
long long f(int n, int k) {
	if (n < k || k == 0 || n == 0)return 0;
	if (n == k || k == 1)return 1;
	return f(n - 1, k - 1) + f(n - 1, k) * k;
}
int main() {
	int n, k;
	cin >> n >> k;
	cout << f(n, k);
	return 0;
}

1316:【例4.6】数的计数(Noip2001)

【题目描述】

我们要求找出具有下列性质数的个数(包括输入的自然数n)。先输入一个自然数n(n≤1000),然后对此自然数按照如下方法进行处理:

不作任何处理;

在它的左边加上一个自然数,但该自然数不能超过原数的一半;

加上数后,继续按此规则进行处理,直到不能再加自然数为止。

【题目分析】

【代码实现】

#include<bits/stdc++.h>
using namespace std;


long long ans = 1;
long long a[10000];
/*记忆化递归*/
long long dfs(int n) {
	if (a[n] != 0) return a[n];
	else {
		a[n]++;
		for (int i = 1; i <= n / 2; i++) {
			a[n] += dfs(i);
		}
		return a[n];
	}
}
int main() {
	int n;
	cin >> n;
	a[1] = 0;
	a[2] = 2;
	cout << dfs(n);
	return 0;
}

1198:逆波兰表达式

【题目描述】

逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3。逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的逆波兰表示法为* + 2 3 4。本题求解逆波兰表达式的值,其中运算符包括+ - * /四个。

【题目分析】

 【代码实现】

#include<bits/stdc++.h>
using namespace std;

char a[105];
double calc() {
	cin >> a;
	switch (a[0]) {
		case '+':
			return calc() + calc();
			break;
		case '-':
			return calc() - calc();
			break;
		case '*':
			return calc() * calc();
			break;
		case '/':
			return calc() / calc();
			break;
		default:
			return atof(a);
			break;
	}
}
int main() {
	printf("%f\n", calc());
	return 0;
}

1199:全排列

【题目描述】

给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。

我们假设对于小写字母有‘a’ <‘b’ < ... <‘y’<‘z’,而且给定的字符串中的字母已经按照从小到大的顺序排列。

【题目分析】

 【代码实现】

#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
char a[15];
char b[15];
bool vis[15];
int len = 0;
void dfs(int n) {
	for (int i = 0; i < len; i++) {
		if (vis[i]) continue;
		b[n] = a[i];
		if (n == len) {
			for (int j = 1; j <= len; j++) printf("%c", b[j]);
			printf("\n");
			return;
		} else {
			vis[i] = 1;
			dfs(n + 1);
			vis[i] = 0;
		}
	}
}
int main() {
	cin >> a;
	len = strlen(a);
	dfs(1);
	return 0;
}

1200:分解因数

【题目描述】

给出一个正整数a,要求分解成若干个正整数的乘积,即a=a1×a2×a3×...×an,并且1<a1≤a2≤a3≤...≤an,问这样的分解的种数有多少。注意到a=a也是一种分解。

【题目分析】

 【代码实现】

#include<bits/stdc++.h>

using namespace std;
#define N 10010
int ans = 0;
int a[N];	//记录数据的内容
int b[N];	//记录数据的访问状态
int n = 0;
void print() {
	for (int i = 1; i <= n; i++)cout << a[i] << " ";
	ans++;
	cout << endl;
}
void f(int t) {
	for (int i = 1; i <= n; i++) {
		if (!b[i]) { 		//该数据没有使用过
			a[t] = i;
			b[i] = 1;
			if (t == n) print();
			else f(t + 1);
			b[i] = 0;
		}
	}
}
int main() {
	cin >> n;
//	for(int i=1;i<=n;i++)cin>>a[i];//读入数据
	f(1);
	cout << ans;
	return 0;
}

1201:菲波那契数列

【题目描述】

菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。给出一个正整数a,要求菲波那契数列中第a个数是多少。

【题目分析】

【代码实现】

#include<bits/stdc++.h>

using namespace std;
int a[25]={0,1,1};

int f(int t){
	if(a[t]!=0) return a[t];
	return a[t]=f(t-1)+f(t-2);;
}

int main(){
	int n,t;
//	cout<<f(3);
	for(int i=1;i<=24;i++) cout<<f(i)<<" ";
	
//	cin>>n;
//	for(int i=1;i<=n;i++){
//		cin>>t;
//		cout<<f(t)<<endl;
//	}

	return 0;
}

1202:Pell数列

【题目描述】

Pell数列a1,a2,a3,...的定义是这样的,a1=1,a2=2,...,an=2*an−1+an−2(n>2)

给出一个正整数 k,要求Pell数列的第 k项模上 32767是多少。

【题目分析】

【代码实现】

#include<bits/stdc++.h>

using namespace std;


int a[1000010] = {0, 1, 2};

int pell(int x) {
	if (a[x] != 0) return a[x];
	return a[x] = (2 * pell(x - 1) + pell(x - 2)) % 32767;
}
int main() {
	for (int i = 1; i <= 1000000; i++) pell(i);
	int n, t;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> t;
		cout << a[t] << endl;
	}
	return 0;
}

1203:扩号匹配问题

【题目描述】

在某个字符串(长度不超过100)中有左括号、右括号和大小写字母;规定(与常见的算数式子一样)任何一个左括号都从内到外与在它右边且距离最近的右括号匹配。写一个程序,找到无法匹配的左括号和右括号,输出原来字符串,并在下一行标出不能匹配的括号。不能匹配的左括号用"$"标注,不能匹配的右括号用"?"标注。

【题目分析】

 【代码实现】

#include<bits/stdc++.h>

using namespace std;
char a[105];
int left1[105],right1[105];
int len,l,r;
void f(int p){
	if(p==len) return;
	if(a[p]=='(') left1[l++]=p;
	if(a[p]==')'){
		if(l>0)l--;
		else right1[r++]=p;
	}
	a[p]=' ';
	f(p+1);	
}
int main(){
	while(cin>>a){
		cout<<a<<endl;
		len=strlen(a);
		l=r=0;
		f(0);
		for(int i=0;i<l;i++){
			a[left1[i]]='$';
		}
		for(int i=0;i<r;i++){
			a[right1[i]]='?';
		}
		for(int i=0;i<len;i++) cout<<a[i];
		cout<<endl;
	}
	
	return 0;
}

1204:爬楼梯

【题目描述】

树老师爬楼梯,他可以每次走1级或者2级,输入楼梯的级数,求不同的走法数。例如:楼梯一共有3级,他可以每次都走一级,或者第一次走一级,第二次走两级,也可以第一次走两级,第二次走一级,一共3种方法

【题目分析】

【代码实现】

#include<bits/stdc++.h>

using namespace std;

int resolve(int n){
	if(n==1) return 1;
	if(n==2) return 2;
	
	return resolve(n-1)+resolve(n-2);

}

int main(){
	int n;
	while(cin>>n){
		cout<<resolve(n)<<endl;	    
	}

	return 0;
}

1205:汉诺塔问题

【题目描述】

约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到中间的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。

这是一个著名的问题,几乎所有的教材上都有这个问题。由于条件是一次只能移动一个盘,且不允许大盘放在小盘上面,所以64个盘的移动次数是:18,446,744,073,709,551,615

这是一个天文数字,若每一微秒可能计算(并不输出)一次移动,那么也需要几乎一百万年。我们仅能找出问题的解决方法并解决较小N值时的汉诺塔,但很难用计算机解决64层的汉诺塔。

假定圆盘从小到大编号为1, 2, ...

【题目分析】

 【代码实现】

#include<bits/stdc++.h>

using namespace std;

void f(int n,char a, char b,char c){
	if(n==0) return;
	f(n-1,a,c,b);
	printf("%c->%d->%c\n",a,n,b);
//	cout<<a<<"->"<<n<<"->"<<b<<endl;
	f(n-1,c,b,a);
}

int main(){
	int n;
	char a,b,c;
	cin>>n>>a>>b>>c;
	f(n,a,b,c);

	return 0;
}

1206:放苹果

【题目描述】

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

【题目分析】

 【代码实现】

#include <bits/stdc++.h>

using namespace std;


int f(int m, int n) {
	if ( n == 1 || m == 1 || m == 0) return 1;
	if (m < n) return f(m, m);
	return f(m, n - 1) +  f(m - n, n);
}
int main() {
	//input data
	int t;
	cin >> t;
	while (t--) {
		int m, n;
		cin >> m >> n;
		cout << f(m, n) << endl;
	}

	return 0;
}

1207:求最大公约数问题

【题目描述】

给定两个正整数,求它们的最大公约数。

【题目分析】

 【代码实现】

#include <bits/stdc++.h>

using namespace std;

int gcd(int m, int n) {
	if (n == 0) return m;
	else return gcd(n, m % n);
}
int main() {
	//input data
	int m, n;
	cin >> m >> n;
	cout << gcd(m, n);
	return 0;
}

1208:2的幂次方表示

【题目描述】

 【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

void f(int n, int k) {
	if (n == 1) {
		if (k == 1) printf("2");
		else if(k==0||k==2)  printf("2(%d)", k);
		else {
			printf("2(");
			f(k,0);
			printf(")");
		}
		return;
	}
	f(n / 2, k + 1);
	if (n % 2 == 1) {
		if (k == 1) printf("+2");
		else if(k==0||k==2)  printf("+2(%d)", k);
		else {
			printf("+2(");
			f(k,0);
			printf(")");
		}
	}
}
int main() {
	//input data
	int n;
	cin >> n;
	f(n, 0);

	return 0;
}

1209:分数求和

【题目描述】

 【题目分析】

 【代码实现】

#include <bits/stdc++.h>

using namespace std;

int gcd(int m, int n) {
	if (n == 0) return m;
	else return gcd(n, m%n);
}
int main() {
	//input data
	int k, n, m, a, b;
	char c;
	cin >> k;
	k--;
	cin >> m >> c >> n;
	while (k--) {
		cin >> a >> c >> b;
		int mm = a * n + b * m;
		int nn = n * b;
		int kk = gcd(mm, nn);
		m = mm / kk, n = nn / kk;
	}
	if (n == 1) cout << m;
	else
		cout << m << "/" << n;
	return 0;
}

1210:因子分解

【题目描述】

输入一个数,输出其素因子分解表达式。

【题目分析】

 【代码实现】

#include <bits/stdc++.h>

using namespace std;

int a[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};

void f(int n, int m, int sum) {
	if (n == 1) {
		if (sum == 1) cout << a[m] ;
		if (sum > 1) cout << a[m] << "^" << sum;
		return ;
	}
	if (n % a[m] == 0) {
		sum++;
		f(n / a[m], m, sum);
	} else {
		if (sum == 1) cout << a[m] << "*";
		if (sum > 1) cout << a[m] << "^" << sum << "*";
		f(n, m + 1, 0);
	}
}
int main() {
	//input data
	int n;
	cin >> n;
	f(n, 0, 0);

	return 0;
}

1211:判断元素是否存在

【题目描述】

有一个集合M是这样生成的:(1) 已知k是集合M的元素; (2) 如果y是M的元素,那么,2y+1和3y+1都是M的元素;(3) 除了上述二种情况外,没有别的数能够成为M的一个元素。

问题:任意给定k和x,请判断x是否是M的元素。这里的k是无符号整数,x 不大于 100000,如果是,则输出YES,否则,输出NO。

【题目分析】

 【代码实现】

#include<bits/stdc++.h>

using namespace std;

bool check(int k, int x) {
	if (x == k)return true;
	if (x > k) return check(2 * k + 1, x) || check(3 * k + 1, x);
	if (x < k) return false;
}
int main() {
	int x, k;
	scanf("%d,%d", &k, &x);
	if (check(k, x)) cout << "YES";
	else cout << "NO";
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值