一本通 2.3.1 递推算法

  • Post author:
  • Post category:其他


1312:【例3.4】昆虫繁殖

【题目描述】

科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强。每对成虫过x个月产y对卵,每对卵要过两个月长成成虫。假设每个成虫不死,第一个月只有一对成虫,且卵长成成虫后的第一个月不产卵(过x个月产卵),问过z个月以后,共有成虫多少对?0≤x≤20,1≤y≤20,x≤z≤500。


【题目分析】

用数组a表示成虫的数量,b表示卵的数量,有

a[n]=a[n-1]+b[n-2]

b[n]=y*a[n-x]


【代码实现】

#include<bits/stdc++.h>

using namespace std;

long long a[55], b[55];

/* 1312:【例3.4】昆虫繁殖 */

int main() {
	int x, y, z;
	cin >> x >> y >> z;
	//初始条件
	for (int i = 0; i <= x; i++) {
		a[i] = 1;
		b[i] = 0;
	}
	//递推过程
	for (int i = x + 1; i <= z + 1; i++) {
		a[i] = b[i - 2] + a[i - 1];
		b[i] = a[i - x] * y;
	}
	//输出结果
	cout << a[z + 1];
	return 0;
}

1313:【例3.5】位数问题

【题目描述】

在所有的N位数中,有多少个数中有偶数个数字3?由于结果可能很大,你只需要输出这个答案对12345取余的值。


【题目分析】


【代码实现】

#include<bits/stdc++.h>
using namespace std;
int a[1005], b[1005];
int main() {
	int n;
	cin >> n;
	if (n == 1) {
		cout << 9;
		return 0;
	}
	a[1] = 8; //从高位到低位思考 如果从低位到高位思考会少数量
	b[1] = 1;
	for (int i = 2; i <= n; i++) {
		a[i] = (a[i - 1] * 9 + b[i - 1]) % 12345;
		b[i] = (b[i - 1] * 9 + a[i - 1]) % 12345;
	}
	cout << a[n];
	return 0;
}

1314:【例3.6】过河卒(Noip2002)

【题目描述】

棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上的某一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图3-1中的C点和P1,……,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点(0,0)、B点(n, m) (n,m为不超过20的整数),同样马的位置坐标是需要给出的,C≠A且C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。


【题目分析】


【代码实现】

#include<bits/stdc++.h>

using namespace std;
/*使用两个数组进行求解*/
int main() {
	int a, b, x, y;
	cin >> a >> b >> x >> y;

	int map_data[22][22] = {};
	long long data[22][22] = {};
	//初始化map位置
	map_data[x][y] = 1;
	if (x + 1 <= a && y + 2 <= b) map_data[x + 1][y + 2] = 1;
	if (x + 2 <= a && y + 1 <= b) map_data[x + 2][y + 1] = 1;
	if (x - 1 >= 0 && y + 2 <= b) map_data[x - 1][y + 2] = 1;
	if (y - 2 >= 0 && x + 1 <= a) map_data[x + 1][y - 2] = 1;
	if (x - 1 >= 0 && y - 2 >= 0) map_data[x - 1][y - 2] = 1;
	if (y - 1 >= 0 && x + 2 <= a) map_data[x + 2][y - 1] = 1;
	if (x - 2 >= 0 && y + 1 <= b) map_data[x - 2][y + 1] = 1;
	if (x - 2 >= 0 && y - 1 >= 0) map_data[x - 2][y - 1] = 1;
	//初始化边界条件
	data[0][0] = 1;
	for (int i = 1; i <= a; i++) {
		if (map_data[i][0] == 0)data[i][0] = data[i - 1][0];
	}
	for (int i = 1; i <= b; i++) {
		if (map_data[0][i] == 0)data[0][i] = data[0][i - 1];
	}
	//逐层递推
	for (int i = 1; i <= a; i++) {
		for (int j = 1; j <= b; j++) {
			if (map_data[i][j] != 1)data[i][j] = data[i - 1][j] + data[i][j - 1];
			else  data[i][j] = 0;
		}
	}
	cout << data[a][b];
}

1188:菲波那契数列(2)

【题目描述】

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


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

int a[1000005];
int main() {
	//input data
	a[1] = 1;
	a[2] = 1;
	for (int i = 3; i <= 1000000; i++) {
		a[i] = (a[i - 1] + a[i - 2]) % 1000;
	}
	int n;
	cin >> n;
	while (n--) {
		int m;
		cin >> m;
		cout << a[m] << endl;
	}
	return 0;
}

1189:Pell数列

【题目描述】

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

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


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

int a[1000005];

int main() {
	//input data
	a[1] = 1;
	a[2] = 2;
	for (int i = 3; i <= 1000000; i++) {
		a[i] = (2 * a[i - 1] + a[i - 2]) % 32767;
	}
	int n;
	cin >> n;
	while (n--) {
		int m;
		cin >> m;
		cout << a[m] << endl;
	}
	return 0;
}

1190:上台阶

【题目描述】

楼梯有n(71>n>0)阶台阶,上楼时可以一步上1阶,也可以一步上2阶,也可以一步上3阶,编程计算共有多少种不同的走法。


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

long long a[72];

int main() {
	//input data
	a[0] = 1;
	a[1] = 1;
	a[2] = 2;
	a[3] = a[2] + a[1] + a[0];
	for (int i = 3; i <= 72; i++) {
		a[i] = a[i - 1] + a[i - 2] + a[i - 3];
	}
	int n;
	while (cin >> n, n != 0) {
		cout << a[n] << endl;
	}
	return 0;
}

1191:流感传染

【题目描述】

有一批易感人群住在网格状的宿舍区内,宿舍区为n*n的矩阵,每个格点为一个房间,房间里可能住人,也可能空着。在第一天,有些房间里的人得了流感,以后每天,得流感的人会使其邻居传染上流感,(已经得病的不变),空房间不会传染。请输出第m天得流感的人数。


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

char a[105][105];
int vis[105][105];
int sum = 0;
int _next[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int main() {
	//input data
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			char c;
			scanf("%c", &c);
			if (c == ' ' || c == '\n') {
				j--;
				continue;
			}
			a[i][j] = c;
			if (a[i][j] == '@') {
				vis[i][j] = 1;
			}
		}
	}

	int m;
	cin >> m;
	for (int i = 2; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			for (int k = 1; k <= n; k++) {
				if (a[j][k] == '@' && vis[j][k] == i - 1) {
					for (int l = 0; l < 4; l++) {
						int nx = j + _next[l][0];
						int ny = k + _next[l][1];
						if (nx < 1 || ny < 1 || nx > n || ny > n) continue;
						if (a[nx][ny] == '#' || a[nx][ny] == '@') continue;
						a[nx][ny] = '@';
						vis[nx][ny] = i;
					}
				}

			}
		}
	}
//	for (int i = 1; i <= n; i++) {
//		for (int j = 1; j <= n; j++) {
//			cout << a[i][j];
//		}
//		cout << endl;
//	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (a[i][j] == '@') sum++;
		}
	}
	cout << sum << endl;
	return 0;
}

1192:放苹果

【题目描述】

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


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

int a[15][15];


int main() {
	//input data
	int t, m, n;
	for (int i = 0; i <= 10; i++) {
		a[1][i] = a[0][i] = 1;
		a[i][1] = 1;
		a[i][0] = 0;
	}
	for (int i = 2; i <= 10; i++) {
		for (int j = 2; j <= 10; j++) {
			if (i < j) a[i][j] = a[i][i];
			if (i >= j) a[i][j] = a[i][j - 1] + a[i - j][j];
		}
	}
	cin >> t;
	while (t--) {
		cin >> m >> n;
		cout << a[m][n] << endl;
	}

	return 0;
}

1193:吃糖果

【题目描述】

名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名(盒内共有 N 块巧克力,0<N<20)。妈妈告诉名名每天可以吃一块或者两块巧克力。假设名名每天都吃巧克力,问名名共有多少种不同的吃完巧克力的方案。例如:如果N=1,则名名第1天就吃掉它,共有1种方案;如果N=2,则名名可以第1天吃1块,第2天吃1块,也可以第1天吃2块,共有2种方案;如果N=3,则名名第1天可以吃1块,剩2块,也可以第1天吃2块剩1块,所以名名共有2+1=3种方案;如果N=4,则名名可以第1天吃1块,剩3块,也可以第1天吃2块,剩2块,共有3+2=5种方案。现在给定N,请你写程序求出名名吃巧克力的方案数目。


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

int a[20];
int main() {
	//input data
	a[1] = 1;
	a[2] = 2;
	a[3] = 3;
	int n;
	cin >> n;
	for (int i = 3; i <= n; i++) {
		a[i] = a[i - 1] + a[i - 2];
	}
	cout << a[n];
	return 0;
}

1194:移动路线

【题目描述】

X桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格的坐标为(m,n)。

小明是个调皮的孩子,一天他捉来一只蚂蚁,不小心把蚂蚁的右脚弄伤了,于是蚂蚁只能向上或向右移动。小明把这只蚂蚁放在左下角的方格中,蚂蚁从

左下角的方格中移动到右上角的方格中,每步移动一个方格。蚂蚁始终在方格矩阵内移动,请计算出不同的移动路线的数目。

对于1行1列的方格矩阵,蚂蚁原地移动,移动路线数为1;对于1行2列(或2行1列)的方格矩阵,蚂蚁只需一次向右(或向上)移动,移动路线数也为1……对于一个2行3列的方格矩阵,如下图所示:

蚂蚁共有3种移动路线:

路线1:(1,1) → (1,2) → (1,3) → (2,3)

路线2:(1,1) → (1,2) → (2,2) → (2,3)

路线3:(1,1) → (2,1) → (2,2) → (2,3)


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

long long a[20][20];
int main() {
	//input data
	for (int i = 1; i <= 19; i++) {
		a[i][1] = 1;
		a[1][i] = 1;
	}
	for (int i = 2; i <= 19; i++) {
		for (int j = 2; j <= 19; j++) {
			a[i][j] = a[i - 1][j] + a[i][j - 1];
		}
	}
	int m, n;
	cin >> m >> n;
	cout << a[m][n];
	return 0;
}

1195:判断整除

【题目描述】

一个给定的正整数序列,在每个数之前都插入++号或−−号后计算它们的和。比如序列:1、2、41、2、4共有88种可能的序列:

(+1) + (+2) + (+4) = 7
(+1) + (+2) + (-4) = -1
(+1) + (-2) + (+4) = 3
(+1) + (-2) + (-4) = -5
(-1) + (+2) + (+4) = 5
(-1) + (+2) + (-4) = -3
(-1) + (-2) + (+4) = 1
(-1) + (-2) + (-4) = -7

所有结果中至少有一个可被整数k整除,我们则称此正整数序列可被k整除。例如上述序列可以被3、5、73、5、7整除,而不能被2、4、6、8……2、4、6、8……整除。注意:0、−3、−6、−9……0、−3、−6、−9……都可以认为是3的倍数。


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

int a[10005];
bool f[10005][105];
int main() {
	//input data
	int n, k;
	cin >> n >> k;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		a[i] = a[i] % k;
	}
	f[0][0] = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j < k; j++) {
			if (f[i - 1][j] == 1) {
				f[i][(j + a[i]) % k] = 1;
				f[i][(j - a[i] + k) % k] = 1;
			}
		}
	}
	if (f[n][0] == 1) cout << "YES";
	else cout << "NO";
	return 0;
}

1196:踩方格

【题目描述】

有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:

a、每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;

b、走过的格子立即塌陷无法再走第二次;

c、只能向北、东、西三个方向走;

请问:如果允许在方格矩阵上走n步,共有多少种不同的方案。2种走法只要有一步不一样,即被认为是不同的方案。


【题目分析】


【代码实现】

#include <bits/stdc++.h>

using namespace std;

int a[25];
int main() {
	//input data
	a[1] = 3;
	a[2] = 7;
	int n;
	cin >> n;
	for (int i = 3; i <= n; i++) {
		a[i] = a[i - 1] * 2 + a[i - 2];
	}
	cout << a[n];
	return 0;
}

1197:山区建小学

【题目描述】

政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0<i<m。为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设0<n≤m<500)。请根据给定的m、n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。


【题目分析】


【代码实现】

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

//int a[505];
int a[505][505];
int b[505][505];
int f[505][505];
int main() {
	int m, n;
	cin >> m >> n;
	for (int i = 1; i < m; i++) {
		cin >> a[i][i + 1];
		a[i + 1][i] = a[i][i + 1];
	}
	//计算村庄到村庄之间的距离
	for (int i = 1; i <= m; i++)
		for (int j = i; j <= m; j++) {
			if (i == j || a[i][j] != 0) continue;
			a[j][i] = a[i][j] = a[i][j - 1] + a[j - 1][j];
		}
	//在各村庄之间修学校的距离
	for (int i = 1; i <= m; i++) {
		for (int j = i + 1; j <= m; j++) {
			int mid = (i + j) / 2;
			for (int k = i; k <= j; k++) {
				b[i][j] += a[k][mid];
			}
			b[j][i] = b[i][j];
		}
	}
	//边界条件
	for (int i = 1; i <= m; i++) {
		f[i][1] = b[1][i];
	}
	//动态规划 计算过程
	for (int i = 1; i <= m; i++) {
		for (int j = 2; j <= n; j++) {
			f[i][j] = 1e8;
			for (int k = 1; k <= i; k++) {
				f[i][j] = min(f[i][j], f[k][j - 1] + b[k + 1][i]);
			}
		}
	}
	cout<<f[m][n];
//	for (int i = 1; i <= m; i++) {
//		for (int j = 1; j <= m; j++) {
//			cout << setw(5) << f[i][j];
//		}
//		cout << endl;
//	}

	return 0;
}



版权声明:本文为xuqw11111原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。