Lab1
Q-A
关键在于代码实现欧拉函数
在数论,对正整数n,欧拉函数φ(N)是小于n的正整数中与n互质的数的数目
。如:φ(1)=1 此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。
例如φ(8)=4,因为1,3,5,7均和8互质。
设 :N = P1 ^ q1 * P2 ^ q2 *… * Pn ^ qn.
则:φ(N) = N * (1-1/P1) * (1-1/P2) *… * (1-1/Pn)
只和底数有关,和指数无关。
1 | int euler(int n) |
Q-B
直接用Q-A的欧拉函数即可
Q-C
约瑟夫问题:
n个人围成一圈,按1到n的顺序编号。从第一个人开始报数(从1到m报数),凡报到m的人退出圈子,问最后留下的是原来的第几号。
递推法
1 | int josephus(int n, int m) { |
关键步骤:J(n,m) = (J(n-1,m) + m) % n
这里假设第一个人从0开始计数,那么第一轮淘汰的是m-1
号,即(m-1) mod n
剩余(n-1)个人重新编号,被淘汰者的下一位(即 m % n 号)成为新编号 0,被淘汰者的下一位(即 m % n 号)成为新编号 0。
在 n-1 个人的新问题中,幸存者的编号是J(n-1,m).
那我们将它映射回n个人的原始编号:
新编号 0 对应原始编号 m % n。
新编号 1 对应原始编号 (m+1) % n。
…
新编号 k 对应原始编号 (m + k) % n。
因此,幸存者在 n 个人时的原始编号为:J(n,m) = (J(n-1,m) + m) % n
(这里的J(n-1,m)即上一行中的k)。
在程序中就表示为res = (res + m) % i;
模拟法
1 |
|
关键步骤:pos = (pos + k - 1) % people.size();
,作用是计算下一个要淘汰的人的位置。
假设从pos
开始数k个人,第一个是people[pos]
,那么可知第k个是people[pos+k-1]
。
那么当我们淘汰该人之后,下一个人又要从1开始计数,即 % people.size()
,让计算回到环的开头。people.erase(people.begin() + pos);
:erase()
会删除 people[pos]
,后面的元素自动前移。
直到最后就只剩下一个,也就是pos[0]。
例如:
当前 people = [0,1,2,3,4],pos = 2(淘汰 2)。
删除后 people = [0,1,3,4],pos 仍然指向 2(现在是 3 的位置)。
Q-D
将十进制整数转化成R进制
基本思路:设十进制数为n,则将n不断除R取余,将得到的余数再倒序即为十进制数n的R进制形式。
例如将十进制数30转化为二进制形式:
1 | 以下的除表示数学意义上保留余数的除法 |
那么我们将余数倒序得到11110
即为30的二进制形式。
恰好栈的出入方式是先进后出,那我们就可以将余数按顺序储存到栈中,再按顺序输出,就能得到想要的结果。
代码实现:
1 | string decimalToR(int N, int R) |
注意:超出10的数字用A、B、C这类字母表示。
可以用如下函数:
1 | char getChar(int num) |
Q-E
巧妙利用C语言的输入和输出:scanf("%d+%d=", &n, &m)
即表示输入时需要输入“n+m=”的形式,符合题意。
Q-F
波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的波兰表示法为+ 2 3。波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的波兰表示法为* + 2 3 4。本题求解波兰表达式的值,其中运算符包括+ - * /四个。
思路:对于波兰表达式,我们可以通过从右到左遍历+栈的方式解决。
具体来说就是,从右到左遍历输入值,遇到数字便入栈,遇到符号,便将栈顶两个元素出栈进行运算,再将运算结果重新入栈,最后剩下唯一的数字就是结果。
代码实现:
先通过getline(cin,line)
读入带空格的字符串line
再用istringstream iss(line)
储存分割后的每个符号或数字,因为输入的符号或数字是用空格分开的,这句就相当于把一个个不含空格的字符串存在iss里
再将这些元素存入字符数组,以便后续入栈
1 | while (iss >> token) |
之后从右到左遍历这个数组,是数字就入栈,是符号就把栈顶两个元素拿出来进行计算,再将计算结果入栈。
1 | for (int i = tokens.size() - 1; i >= 0; --i) |
注:stod
是字符串转为浮点数(string to double)isOperator()
判断字符串是否为运算符calc()
计算两个数运算结果
Q-G
基本的二路归并
两个数组都是从小到大排序,要做的就是分别从头遍历两个数组,并进行比较,小的插入新数组,再移动到下一个继续比较,直到有一方结束遍历,就将剩下的全部插到新数组末尾。
代码实现:
1 | vector<int> q1(n), q2(n); |