NENU OJ算法2例题
剩余oj例题的代码思路已更新到本人网站上,指路:DODOLA’s
这学期写算法2并不想写详细思路(出于ddl再也不用关心小组啦的自由),不过如果有想交流的也可以评论区或者私信,学校oj的题大多比较简单,这里的所有代码或许只保证通过学校的弱测试数据,因为其他地方OJ我还没有试过。
目录:
文章目录
- NENU OJ算法2例题
算法2递归A
1241: A001 猴子吃桃
题目描述
猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半另加一个。到第10天早上想再吃时,就只剩下一个桃子了。求第1天共摘了多少个桃子。
输入
输入第一行为正整数n,为测试数据组数。后面n行为测试数据,每组测试数据包括两个整数m,k,分别表示第m(m>1)天后剩余的桃子数k(k>=0)。
输出
输出猴子第一天摘的桃子数,每组数据占一行。
样例输入
2
2 2
3 0
样例输出
6
6
AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;cin >> n;
while (n--) {
int m, k;cin >> m >> k;
int sum = k;
for (int i = 0;i < m - 1;i++) {
sum++;
sum *= 2;
}
cout << sum << endl;
}
return 0;
}
1242: A002 最大公约数
题目描述
输入两个正整数,求其最大公约数。
数论中有一个求最大公约数的算法称为辗转相除法,又称欧几里德算法。其基本思想及执行过程为(设m为两正整数中较大者,n为较小者):
(1)令u=m,v=n;
(2)取u对v的余数,即r=u%v,如果r的值为0,则此时v的值就是m和n的最大公约数,否则执行第(3)步;
(3)u=v,v=r,即u的值为v的值,而v的值为余数r。并转向第(2)步。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括两个正整数m和n。
输出
n行,每行输出对应一个输入。输出应是一个正整数,为m和n的最大公约数。
样例输入
2
48 32
15 5
样例输出
16
5
AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;cin >> t;
while (t--) {
int m, n;cin >> m >> n;
int yu = m % n;
while (yu) {
m = n;n = yu;
yu = m % n;
}
cout << n << endl;
}
return 0;
}
1243: A003 经典的Hanoi(汉诺塔)问题
题目描述
有一个汉诺塔,塔内有A,B,C三个柱子。起初,A柱上有n个盘子,依次由大到小、从下往上堆放,要求将它们全部移到C柱上;在移动过程中可以利用B柱,但每次只能移到一个盘子,且必须使三个柱子上始终保持大盘在下,小盘在上的状态。要求编程输出移动的步骤。
输入
输入文件中包含多行,每行为一个整数n,代表初始A柱子上的盘子的个数。
输出
对输入文件中的每个整数n列出具体的汉诺塔移动步骤。两组输出之间有一空行。
样例输入
3
1
样例输出
A-->C
A-->B
C-->B
A-->C
B-->A
B-->C
A-->C
A-->C
AC代码
#include<bits/stdc++.h>
using namespace std;
void hanoi(int n, int from, int to) {
if (n == 0) return; // 全部移完,终止递归
// 把from位置上的上面的n-1个移到不是from也不是to的位置
hanoi(n - 1, from, (3 - from - to));
// 移动最底下的最大的那个,并输出记录
cout << char(from + 'A') << "-->" << char(to + 'A') << endl;
// 把之前移走的n-1个移到to位置
hanoi(n - 1, (3 - from - to), to);
}
int main() {
int n;
while (cin >> n) {
hanoi(n, 0, 2);
cout << "\n";
}
return 0;
}
1244: A004 菲波那契数列
题目描述
菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。给出一个正整数a,要求菲波那契数列中第a个数是多少。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a(1 <= a <= 20)。
输出
输出有n行,每行输出对应一个输入。输出应是一个正整数,为菲波那契数列中第a个数的大小。
样例输入
4
5
2
19
1
样例输出
5
1
4181
1
AC代码
#include<bits/stdc++.h>
using namespace std;
int fib(int n) {
if (n == 1 || n == 2)return 1;
return fib(n - 1) + fib(n - 2);
}
int main() {
int t;cin >> t;
while (t--) {
int a;cin >> a;
cout << fib(a) << endl;
}
return 0;
}
1245: A005 另一个Fibonacci数列
题目描述
定义另外一个Fibonacci数列:F(0)=7,F(1)=11,F(n)=F(n-1)+F(n-2),(n≥2)。
输入
输入文件中包含多行,每行为一个整数n,n<1000000。
输出
对输入文件中的每个整数n,如果F(n)能被3整除,输出yes,否则输出no。
样例输入
0
1
2
3
样例输出
no
no
yes
no
AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
long long na;
while (cin >> na) {
if (na % 8 == 2 || na % 8 == 6)cout << "yes\n";
else cout << "no\n";
}
return 0;
}
1246: A006 分形(Fractal)
题目描述
分形是存在“自相似”的一个物体或一种量,从某种技术角度来说,这种“自相似”是全方位的。
盒形分形定义如下:
度数为1的分形很简单,为:
X
度数为2的分形为:
X X
X
X X
如果用B(n-1)代表度数为n-1的盒形分形,则度数为n的盒形分形可以递归地定义为:
B(n-1) B(n-1)
B(n-1)
B(n-1) B(n-1)
你的任务是输出度数为n的盒形分形。
输入
输入文件包含多个测试数据,每个测试数据占一行,包含一个正整数n,n ≤ 7。输入文件的最后一行为-1,代表输入结束。
输出
对每个测试数据,用符号“X”表示输出盒形分形。在每个测试数据对应的输出之后输出一个短划线符号“-”,在每行的末尾不要输出任何多余的空格,否则得到的是“格式错误”的结果。
样例输入
2
3
-1
样例输出
X X
X
X X
-
X X X X
X X
X X X X
X X
X
X X
X X X X
X X
X X X X
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxlen = pow(3, 8);
// string mp[maxlen];
char mp[maxlen][maxlen];
int xpos[maxlen];
void tocpyRec(int deg, int tox, int toy,int fillblank) {
int len = pow(3, deg - 1);
// 左上角标记
for (int i = 0;i < len;i++) {
for (int j = 0;j < len;j++) {
// cout << mp[i][j] << ":" << i << "-" << j << endl;
if (fillblank)
mp[tox * len + i][toy * len + j] = ' ';
else
mp[tox * len + i][toy * len + j] = mp[i][j];
}
}
}
void fw(int deg) {
if (deg > 1) {
fw(deg - 1);
}
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
if ((i + j) % 2 == 0 && (i || j)) {
// 有内容的块坐标
tocpyRec(deg - 1, i, j, 0);
}
else if (i || j) {
tocpyRec(deg - 1, i, j, 1);
}
}
}
}
int main() {
mp[0][0] = 'X';
int n;
int flag = 0;
while (cin >> n && n != -1) {
if (flag)cout << "-\n";
flag = 1;
fw(n);
int len = pow(3, n - 1);
for (int i = 0;i < len;i++)
for (int j = 0;j < len;j++)
if (mp[i][j] == 'X')
xpos[i] = j;
for (int i = 0;i < len;i++) {
for (int j = 0;j <= xpos[i];j++) {
cout << mp[i][j];
}
cout << endl;
}
}
return 0;
}
1247: A007 二叉树
题目描述
如图所示,由正整数1, 2, 3, …组成了一棵无限大的二叉树。从某一个结点到根结点(编号是1的结点)都有一条唯一的路径,比如从10到根结点的路径是(10, 5, 2, 1),从4到根结点的路径是(4, 2, 1),从根结点1到根结点的路径上只包含一个结点1,因此路径就是(1)。对于两个结点x和y,假设他们到根结点的路径分别是(x1, x2, … ,1)和(y1, y2, … ,1)(这里显然有x = x1,y = y1),那么必然存在两个正整数i和j,使得从xi 和 yj开始,有xi = yj , xi + 1 = yj + 1, xi + 2 = yj + 2,… 现在的问题就是,给定x和y,要求xi(也就是yj)。
输入
输入有多行,每行包括两个正整数x和y,这两个正整数都不大于1000。
输出
每行输出只有一个正整数xi。
样例输入
10 4
样例输出
2
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 12;
int ax[N], ay[N];
int main() {
int x, y;
// 找重合的路径
while (cin >> x >> y) {
int kx = 0;
while (x) {
ax[kx++] = x % 2;
x /= 2;
}
int ky = 0;
while (y) {
ay[ky++] = y % 2;
y /= 2;
}
int kmii = kx > ky ? ky : kx;
int ans = 0;
for (int i = 1;i <= kmii;i++) {
if (ax[kx - i] == ay[ky - i]) {
ans <<= 1;
ans += ax[kx - i];
}
else break;
}
cout << ans << endl;
}
return 0;
}
1248: A008 波兰表达式
题目描述
波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的波兰表示法为+ 2 3。波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的波兰表示法为* + 2 3 4。本题求解波兰表达式的值,其中运算符包括+ - * /四个。
输入
输入第一行为一个整数n,然后是n行,每行为一组测试数据,其中运算符和运算数之间都用空格分隔,运算数是浮点数。
输出
输出n行,每行表达式的值,保留3位小数输出。
样例输入
1
* + 11.0 12.0 + 24.0 35.0
样例输出
1357.000
AC代码
#include<bits/stdc++.h>
using namespace std;
double dox() {
string st;cin >> st;
switch (st[0])
{
case '+':
return dox() + dox();
case '-':
return dox() - dox();
case '/':
return dox() / dox();
case '*':
return dox() * dox();
default:break;
}
return atof(st.c_str());
}
int main() {
int t;cin >> t;
while (t--) {
cout << fixed << setprecision(3) << dox() << endl;
}
return 0;
}
1249: A009 放苹果
题目描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法(用K表示)?注意:5,1,1和1,5,1 是同一种分法。
输入
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1 <= M,N <= 10。
输出
对输入的每组数据M和N,用一行输出相应的K。
样例输入
1
7 3
样例输出
8
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 15;
int dp[N][N];
int divx(int apl, int pla) {
if (apl == 0 || pla == 1)
return dp[apl][pla] = 1;
if (pla > apl)
return dp[apl][pla] = divx(apl, apl);
return dp[apl][pla] = divx(apl, pla - 1) + divx(apl - pla, pla);
}
int main() {
int t;cin >> t;
int m, n;
while (t--) {
cin >> m >> n;
cout << divx(m, n) << endl;
}
return 0;
}
1250: A010 递归练习1
题目描述
有5个人坐在一起,问第5个人多少岁?他说比第4个人大两岁。问第4个人的岁数,他说比第3个人大两岁。问第3个人的岁数,又说比第2个人大两岁。问第2个人的岁数,说比第1个人大两岁。最后问第1个人的岁数,他说是10岁。请问第5个人多少岁?
输入
输入有多行,每行3个整数,依次为m,n,k。m表示一共有几个人,n表示大的岁数,k表示第一个人的岁数。
输出
输出第m个人的岁数,每个一行。
样例输入
5 2 10
样例输出
18
AC代码
#include<bits/stdc++.h>
using namespace std;
int m, n, k;
int age(int ind) {
if (ind == 1)return k;
return age(ind - 1) + n;
}
int main() {
while (cin >> m >> n >> k) {
cout << age(m) << endl;
}
return 0;
}
1251: A011 递归练习2
题目描述
根据递推式子C(m,n)=C(m-1,n)+C(m-1,n-1),求组合数C(m,n)。注意递推的终止条件是C(m,1)=m;以及一些m和n取值的一些特殊情况,如m < 0或n < 0或m < n时,C(m,n)值为0,m和n相等时,C(m,n)=1等。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数m和一个正整数n。
输出
输出组合数C(m,n)。
样例输入
2
1 100
100 1
样例输出
0
100
AC代码
#include<bits/stdc++.h>
using namespace std;
int C(int m, int n) {
if (n == 1)return m;
if (m < 0 || n < 0 || m < n)return 0;
if (m == n)return 1;
return C(m - 1, n) + C(m - 1, n - 1);
}
int main() {
int t;cin >> t;
while (t--) {
int m, n;cin >> m >> n;
cout << C(m, n) << endl;
}
return 0;
}
1252: A012 递归练习3
题目描述
核反应堆中有α和β两种粒子。每秒钟内一个α粒子可以产生3个β粒子,而一个β粒子可以产生1个α粒子和2个β粒子。若在t=0时刻反应堆中有一个α粒子,求t时刻反应堆中分别有多少个α粒子和β粒子。
输入
输入有多个整数t,每个一行。
输出
输出t时刻反应堆里分别有多少个α粒子和β粒子。
样例输入
6
样例输出
183 546
AC代码
#include<bits/stdc++.h>
using namespace std;
pair<int, int> qut(int n) {
if (n == 0)return make_pair(1, 0);
int tempa = qut(n - 1).first, tempb = qut(n - 1).second;
int a = tempb, b = 3 * tempa + 2 * tempb;
return make_pair(a, b);
}
int main() {
int t;
while (cin >> t) {
cout << qut(t).first << " " << qut(t).second << endl;
}
return 0;
}
插一句
:这里用了pair数据类型,或许有同学并没有接触到…一般函数会返回1个值,有时候想返回两个或以上的时候可以试试自定义struct数据类型,再去定义一个struct的函数,不过c++自有一个pair可以用,还是挺方便的。
1253: A013 红与黑
题目描述
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
输入
包括多个数据集合。每个数据集合的第一行是两个整数W和H,分别表示x方向和y方向瓷砖的数量。W和H都不超过20。在接下来的H行中,每行包括W个字符。每个字符表示一块瓷砖的颜色,规则如下
1)‘.’:黑色的瓷砖;
2)‘#’:白色的瓷砖;
3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。
当在一行中读入的是两个零时,表示输入结束。
输出
对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。
样例输入
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
0 0
样例输出
45
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxh = 25;
string mp[maxh];
int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };
int w, h;
int move(int x, int y, int allstep) {
for (int i = 0;i < 4;i++) {
int nx = x + dx[i], ny = y + dy[i];
if (nx > -1 && nx<h && ny>-1 && ny < w && mp[nx][ny] == '.'){
mp[nx][ny] = '#';
allstep = move(nx, ny, allstep + 1);
}
}
return allstep;
}
int main() {
while (cin >> w >> h && w != 0 && h != 0) {
int si, se;
for (int i = 0;i < h;i++) {
cin >> mp[i];
if (mp[i].find("@") != string::npos) {
si = i;se = mp[i].find("@");
}
}
int steps = move(si, se, 1);
cout << steps << endl;
}
return 0;
}
1254: A014 城堡问题
题目描述
1 2 3 4 5 6 7
#############################
1 # | # | # | | #
#####—#####—#—#####—#
2 # # | # # # # #
#—#####—#####—#####—#
3 # | | # # # # #
#—#########—#####—#—#
4 # # | | | | # #
#############################
(图 1)
‘#’ = Wall
‘|’ = No wall
‘-’ = No wall
图1是一个城堡的地形图。请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成m*n(m≤50,n≤50)个方块,每个方块可以有0~4面墙。
输入
程序从标准输入设备读入数据。第一行是两个整数,分别是南北向、东西向的方块数。在接下来的输入行里,每个方块用一个数字(0≤p≤50)描述。用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。输入的数据保证城堡至少有两个房间。
输出
城堡的房间数、城堡中最大房间所包括的方块数。
样例输入
4
7
11 6 11 6 3 10 6
7 9 6 13 5 15 5
1 10 12 7 13 7 5
13 11 10 8 10 12 13
样例输出
5
9
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 60;
int wall[N][N], fw[N][N];
int roomnum = 0, sizea = 0;
void dfs(int x, int y) {
// 查找点(x,y)的信息
if (fw[x][y]) return;
sizea++;
fw[x][y] = roomnum;
if ((wall[x][y] & 1) == 0)dfs(x, y - 1);
if ((wall[x][y] & 2) == 0)dfs(x - 1, y);
if ((wall[x][y] & 4) == 0)dfs(x, y + 1);
if ((wall[x][y] & 8) == 0)dfs(x + 1, y);
}
int main() {
int h, w;cin >> h >> w;
for (int i = 1;i <= h;i++){
for (int j = 1;j <= w;j++){
cin >> wall[i][j];
}
}
int maxroom = 0;
for (int i = 1;i <= h;i++) {
for (int j = 1;j <= w;j++) {
if (!fw[i][j]) {
// (i,j)没被找过(新的area)
roomnum++;
dfs(i, j);
maxroom = max(maxroom, sizea);
sizea = 0;
}
}
}
cout << roomnum << endl << maxroom << endl;
return 0;
}
/*
2
1 4
8
*/
1255: A015 分解因式
题目描述
给出一个正整数a,要求分解成若干个正整数的乘积,即a = a1 * a2 * a3 * … * an,并且1 < a1 <= a2 <= a3 <= … <= an,问这样的分解的种数有多少。注意到a = a也是一种分解。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a (1 < a < 32768)。
输出
n行,每行输出对应一个输入。输出应是一个正整数,指明满足要求的分解的种数。
样例输入
2
2
20
样例输出
1
4
AC代码
#include<bits/stdc++.h>
using namespace std;
int ans = 0;
void dfs(int tar, int now) {
if (tar != 1) {
for (int i = now;i <= tar;i++)
if (tar % i == 0)
dfs(tar / i, i);
}
else {
ans++;return;
}
}
int main() {
int t;cin >> t;
while (t--) {
ans = 0;
int n;cin >> n;
if (n == 2) {
cout << 1 << endl;
continue;
}
dfs(n, 2);
cout << ans << endl;
}
return 0;
}
1256: A016 数字拼凑
题目描述
现在给你这样一个任务,要求找出具有下列性质数的个数(包含输入的正整数 n)。
先输入一个正整数 n(n <= 500),然后对此正整数按照如下方法进行处理:
- 不作任何处理;
- 在它的左边拼接一个正整数,但该正整数不能超过原数的一半或者是上一个被拼接数的一半;
- 加上数后,继续按此规则进行处理,直到不能再加正整数为止。
输入
一个正整数n。
输出
一个正整数,表示具有该性质数的个数。
样例输入
6
样例输出
6
AC代码
#include<bits/stdc++.h>
using namespace std;
int fx[1010];
int f(int n) {
if (n == 1)return 1;
if (fx[n])return fx[n];
int cnt = 0;
for (int i = 1;i <= n / 2;i++)
cnt += f(i);
return fx[n] = cnt + 1;
}
int main() {
int n;
cin >> n;
cout << f(n) << endl;
return 0;
}