第一题
这个原题目和之前的作业题目基本没差,这里给出优化之后的代码
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n;
double s = 1;
long long n_fac = 1;
cin >> n;
for(int i=1; i<=n; i++) {
n_fac *= i;
s += 1.0 / n_fac;
}
cout << fixed << setprecision(6) << "s = " << s << endl;
return 0;
}
第二题
数组排序是很经典的问题,这里简单介绍一种冒泡排序(升序)的算法,思路就是将数组分为两部分,一部分拍好序,一部分没有,每次都遍历没有排好序的那一部分,将较大的元素往后排/(较小的元素往前排),每一趟确定最大/最小的一个元素,循环n次之后就自然可以得到拍好顺序的数组,这里其实很容易和另一种叫选择插入排序的算法弄混,简单来说,选择插入是每次选择最小的元素插入到已经排好序的数组中,它们之间的区别是,冒泡排序只关注当前元素和下一个元素之间的大小关系,而选择插入是选择最小的元素,这就导致了冒泡排序中元素的交换次数往往大于选择插入排序,同时冒泡排序具有稳定性,而选择插入排序没有。具体的算法和之间对比可以看这里冒泡和选择插入算法对比。
回归到这个题目,实际上就是一个将升序转换为降序的过程,实在不行甚至可以在升序排列之后再遍历依次转化为降序排列,但是其实问题应该不难
#include <iostream>
using namespace std;
int main()
{
int n;
int a[100];
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (a[j] < a[j + 1]) {
int t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
for (int i = 0; i < n; i++) {
if (i != 0) {
cout << ' ';
}
cout << a[i];
}
cout << endl;
return 0;
}
第三题
经典题目了,复习一下之前题目中提到的gcd和最小公倍数即可
#include <iostream>
using namespace std;
int main(void)
{
int m, n, t, a, b;
cin >> m >> n;
a = m * n;
t = m % n;
while (t != 0) {
m = n;
n = t;
t = m % n;
}
cout << "最大公约数是:" << n << endl;
cout << "最小公倍数是:" << a / n << endl;
return 0;
}
第四题
这个按照题目描述做就可以了,但是很多同学会写出死循环,常见的几个写出死循环的原因有
1.首先是双层循环使用同一个变量比如这样
for(int i=0;i<n;i++)
{
for( i=1;i<10;i++)
{
//其他代码块
}
}
一个比较好的习惯是如果你需要使用到循环作为判断依据的变量i的值的时候,用一个临时变量获取i的值做判断,而如果你需要针对它本身进行操作,建议for循环的循环结束后执行的语句那一部分多加思考,for循环一般用于已经知道循环次数的循环中,while循环一般用于未知次数的循环中
2.另一个就是写while(1)再依据某个判断条件进行break退出,实际上这样很有可能出现的问题是逻辑错误或者未赋初值导致无法进入break所在的代码块,程序陷入死循环,一般情况下,while循环使用时,你需要先想清楚循环的退出条件再进行执行
3.一个很好检测有没有死循环的方法就是在循环结束之后写一条输出语句,帮助你判断程序是否进入了死循环(头歌上的话,就是看看是否超时,正常情况下除非循环计算了几千亿次时间是够的,超时基本等于死循环)
#include <iostream>
using namespace std;
int main()
{
int n;
// 请在此添加代码,输出整数进入黑洞过程
/********** Begin *********/
cin >> n;
int k = 1;
while(1)
{
int a = n % 10, b, c, t;
n = n / 10;
b = n % 10;
c = n / 10;
if(a < b)
{
t = a; a = b; b = t;
}
if(a < c)
{
t = a; a = c; c = t;
}
if(b < c)
{
t = b; b = c; c = t;
}
t = a * 100 + c - c * 100 - a;
if(t != 495)
cout << k << ":" << a * 100 + b * 10 + c <<"-" << a + b * 10 + c * 100 << "=" << t << endl;
if( t == 495)
cout << k << ":" << a * 100 + b * 10 + c <<"-" << a + b * 10 + c * 100 << "=" << t << endl;
k++;
n = t;
if(t == 495)
break;
}
/********** End **********/
return 0;
}
第五章
这个题目是老题目了,主要用来给同学们复习一下,之前出的地方确实有点早了
#include <iostream>
using namespace std;
int main()
{
int n, flag = 1;
cin >> n;
for (int i=2; i * i <= n; i++) {
if (n % i == 0) {
flag = 0;
break;
}
}
if (flag) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
return 0;
}
第六题
这题一个很显然的思路就是,所需要的是最大的k个素数,那么我们直接从n到1进行遍历,判断当前数字是否是质数,同时如果是质数的话,是第几个质数,这样思路就很清晰了,不用等到把所有质数求出来再取最大的k个质数
#include <iostream>
using namespace std;
int main()
{
int n, k;
int t, m = 0, sum = 0;
cin >> n >> k;
for (t = n; t >= 2; t--) {
int flag = 1;
for (int i = 2; i * i <= t; i++){
if (t % i == 0) {
flag = 0;
break;
}
}
if (flag) {
cout << t << " ";
m++;
sum += t;
if (m == k) break;
}
}
cout << sum;
return 0;
}
第七题
这一关可以这么写
- 直接定义一个长度为n的bool数组(新的标准是运行变量做数组长度的,实在不行定义一个const作为数组长度)
- 从1到k,每次将其倍数对应的数组成员取反,
- 最后输出亮着的灯
一个小技巧是数组定义的时候长度定多一位,这样就可以忽略数组下标从0开始的问题从而简化运算
思考:假如没有k的限制,或者说令k==n,结果会是怎么样呢?答案是只有完全平方数会亮,因为这样本质上就转化为是计算当前数字的因数的个数。
#include <iostream>
using namespace std;
/* 全局数组会自动初始化为0 */
int a[2000];
int main()
{
int n, k, i, j;
cin >> n >> k;
for (i = 1; i <= k; i++) {
for (j = i; j <= n; j += i) {
a[j] = !a[j];
}
}
for (i = 1; i <= n; i++) {
if (!a[i]) continue;
if (i != 1) {
cout << ' ';
}
cout << i;
}
cout << endl;
return 0;
}