本专辑将之前的刷题博客进行了合并和修改,有助于读者和笔者复习回顾
1.1:2023/12/4总结:走马灯数142857和高精度加法
一、走马灯数(神奇的142857)
有一个六位数,由6个不同的数字组成,该数分别乘以2,3,4,5,6将分别得到另外5个不同的六位数,并且依然是这6个数字组成的6位数。
问有几个符合条件的6位数,它们分别等于多少?
1.用一个数组统计一个整数每个数字出现的次数。
2.对于两个数组是否一样。(函数返回为1则表示一样)例题答案思路如下
#include <stdio.h>
void tj(int a[10],int n) //统计整数n每个数字分解一维数组中
{
while(n!=0) //只要n不为0
{
a[n%10]++; //对应的元素值加1,表示这个数字出现了一次
n=n/10; //n缩小10倍
}
}
int db(int a[10],int b[10]) //对比两个一维数组是否完全相等
{
int flag=1; //标志值
for(int i=0;i<10;i++)
if(a[i]!=b[i]) //如果有元素值不相等
flag=0; //将标志值改为0
return flag;
}
int main()
{
for(int i=100000;i<=200000;i++)
{
int a[10]={0}; //定义含有10个元素的数组,初始值都为0
tj(a,i); //将i的各个数字出现的次数,分解到数组a中
int flag=1; //定义了一个标志
for(int j=2;j<=6;j++) //将i分别乘以2到6
{
int k=i*j; //得到乘积
int b[10]={0};
tj(b,k); //将乘积分解到数组b中
if(db(a,b)!=1) //判断数组a与数组b是否不相等
flag=0;
}
if(flag) //标志依然为1,表明,两个数组是完全相等的
{
for(int k=2;k<=6;k++) //输出结果
printf("%d*%d=%d\n",i,k,i*k);
}
}
return 0;
}
我的另外的思路:
//有一个六位数,由6个不同的数字组成,该数分别乘以2,3,4,5,6将分别得到另外5个不同的六位数,并且依然是这6个数字组成的6位数。
//问有几个符合条件的6位数,它们分别等于多少?
//1.用一个数组统计一个整数每个数字出现的次数。
//2.对于两个数组是否一样。(函数返回为1则表示一样)
#include<stdio.h>
int oy(int n,int k)
{
int a[1000]={0},b[1000]={0};
int o=n*k,i,j;
while(n)
{
i=n%10;
a[i]++;
n/=10;
}
while(o)
{
j=o%10;
b[j]++;
o/=10;
}
for(int l=0;l<=9;l++)
{
if(a[l]!=b[l])
return 0;
}
return 1;
}
int main()
{
int u=0;
for(int k=100000;k<=999999;k++)
{
if(oy(k,2)&&oy(k,3)&&oy(k,4)&&oy(k,5)&&oy(k,6))
{
u++;
printf("%d",k);
}
}
printf("总共有%d个",u);
return 0;
}
二、高精度算法
1.求和
在做题是我们会做到比如1+1这种加法运算,但也经常会遇到几十位,甚至几百位的数字 的计算问题,也可能会遇到小数点后几十位,几百位的情况,而我们面对这样的情况下,long long 和 double 的数据范围显然是不够使用 的了(在有符号定义的情况下,int型为2的31次方减1;在无符号定义的情况下,lint型为2的32次方。)。因此这时,我们就需要是使用一个新的算法,叫做高精度算法 .
我们知道char是不用考虑精度的,所以我们就像如果对于10000000000000000000我们直接一位一位打不就行吗,每位范围为【0,9】,故我们在用高精度算法的时候输入是以字符串的形式,用字符串 模拟数字进行计算,再利用类似于数学里的竖式的形式,进行进位和错位。
以666+888为例
输入形式
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int max(int a, int b)
{
if(a > b)
return a;
return b;
}
int main()
{
int a[1000]={0}, b[1000]={0}, c[1000] = {0};//用于计算
char ch1[1000], ch2[1000];//创建两个字符数组来接纳输入的超级大值,c用来存放答案
scanf("%s",&ch1);
scanf("%s",&ch2);//获取
int len1 = strlen(ch1), len2 = strlen(ch2);//测量
int len3 = max(len1, len2) + 1;
for (int i = 0; i < len1; i++)
{
a[len1 - i] = ch1[i] - '0';//将字符串转成数字,然后将其倒置方便计算
}
for (int i = 0; i < len2; i++)//同理
{
b[len2 - i] = ch2[i] - '0';//ASCII代码的相减
}
//高精度加法主体
for (int i = 1; i <= len3; i++)
{
c[i] = c[i] + a[i] + b[i];//正常加法//这就是前面为什么要倒置的原因
c[i + 1] = c[i] / 10;//进位0,1或多
c[i] = c[i] % 10;//剩下
}
if (c[len3] == 0 && len3 > 0) len3--;//判断数组最后一位是否为0,是的不输出,而且len3还应大于0(当输入为0时),否则后面不输出
for(int i=len3;i>0;i--){
printf("%d",c[i]);
}
return 0;
}
好吧,大家可以试试看,其中字符串起的作用是接受作用,而高精度算法是一位一位去算,去输出,所以都是在【0,9】不会爆精度!!
2.0打印特殊方阵
2.1.特殊方阵1-回型方阵(蛇形方阵)
首先是题目
从左上角填上 1开始,顺时针方向依次填入数字。(具体题目如下)
那其实思路很简单,我们可以将画出这个方阵看成四步完成
1.横向1234停止,然后向下
2.向下567,然后向左
3.左8,9,10然后向上
4.上去11 12然后向右(是不是跟第一步是一样的呀)
所以简单就知道要1.递推
画出这个表显然需要2.二维数组
利用这两个工具,我们不妨设一个数组b[20][20](可以再大点)
利用while函数判断
1.越界了吗?(1234到4就得停)
2.下一个数被填了没有(比如第三步12后面的1就被填了,需要判定)
那只要满足这些条件,就可以把1234....的值分别赋到相应的位置;
则此题得解
代码如下:
cpp
//特殊矩阵1-回型矩阵
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,y=0,k=1,x=1;//a代表我们输入的数,x是行,y是列
int b[100][100];
scanf("%d",&a);
while(k<=a*a)//其实只起到一个退出的作用
{
while(y<a&&!b[x][y+1])//1.越界判定变量,2.判断下一个位置有没有有填了的数;
b[x][++y]=k++;//k++好好体会!! 第一步 ;++y,y值一开始是0,判断未触界后立马+1
// 当y=3判定时,执行完后y=4退出
while(x<a&&!b[x+1][y])//此时的y已经确定在最后一排了
b[++x][y]=k++;//第二步
//同理,x为什么一开始为1,第二步后面判定成功后要直接下一位,故初始值为1;
while(y>1&&!b[x][y-1])
b[x][--y]=k++;//第三步
while(x>1&&!b[x-1][y])
b[--x][y]=k++; //第四步
}
for(int i=1;i<=a;i++)
{
for(int j=1;j<=a;j++)
{
printf("%d ",b[i][j]);
}
printf("\n");
}
return 0;
}
2.2特殊方阵2---魔方阵

特殊方阵2-魔方阵
魔方阵是指一个N×N矩阵(在本题中N仅为奇数,且N>1),以自然数1,2,..., N^2为元素进行填充,每个位置上分别放置一个元素,使每行、每列以及主、副对角线上的元素之和都相等。一般的构造方法如下:
- 将1填在第一行的中间一列。
- 从2开始,按照以下规则填数: a. 每个数填在上一个数的右上方。 b. 如果上一个数在第一行,则下一个数填在最后一行同一列。 c. 如果上一个数在最后一列,则下一个数填在第一列同一行。 d. 如果上一个数的右上方已经有数,则下一个数填在上一个数的正下方。
- 重复步骤2,直到填满所有的位置。
- 检查每行、每列以及主、副对角线上的元素之和是否相等,如果相等,则构造成功,否则失败。
比如输入3(即3*3的魔方阵)
图像如下:

不难发现每次1都填充在第一行中间位置
1的相对位置规律寻找:
3*3:第二个
5*5:第三个
7*7:不难推出第四个(即本身加1除以2)
注意:由于数组的排序由0开始,所以实际在运用1的列变量y=(n+1)/2后面我们需要手动减1;
再研究5*5图像

可以看见那个右上方的操作可以用
x=(x1+1)%n;表示
所以代码如下:
cpp
//魔方阵
#include<stdio.h>
int main()
{
int n,x=0,y=0,a[100][100]={0},i;
scanf("%d",&n);//输入界
y=(n+1)/2-1;
a[0][y]=1;
for(i=2;i<=n*n;i++)
{
int x1=x,y1=y;//用于找到上一个坐标
x=(x+(n-1))%n;//向下移动两格,除尽了取余数//这里实现了在右上方
y=(y+1)%n;//向右一格
if(a[x][y]!=0)//如果下一个不为0,向下填充!!!!
{
x=(x1+1)%n;
y=y1;
}
a[x][y]=i;
}
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
printf("%5d",a[j][k]);
}
printf("\n");
}
return 0;
}
如果对您有帮助,我不胜荣幸!!
3.0猜数字小游戏和冒泡排序

一点灵感代码
1.冒泡排序(数字排序)
2.猜数字
猜数字的游戏可以是随机生成一个随机数,以时间为种子,一定程度上增加了随机性,防止在某些软件中无法实现随机
后面以输入的数为基础用if判断即可
冒泡排序
随机生成一堆随机数,将其排序;;
便于理解冒泡排序的定义
cpp
//#include<bits/stdc++.h>
//int main()
//{
// srand(time(NULL)); //以时间为种子;
// int a=rand()%1000,n; //这里是使生成的随机数在0-1000之间
// printf("欢迎来到王者猜数字!\n游戏开始!!\n请在0-1000猜一个数字:\n");
// scanf("%d",&n);
// while(1)
// {
//
// if(n>a)
// {
// printf("好像有点大,往小的猜:");
// scanf("%d",&n);
// }
// if(n<a)
// {
// printf("好像有点小,往大猜:");
// scanf("%d",&n);
// }
// if(n==a)
// {
// printf("哈哈,猜对了,你跟我想得一样!!!");
// break;
// }
// }
// return 0;
//}
//数字排序--------便于理解冒泡排序
#include<bits/stdc++.h>//包含所有的头文件
int main()
{
srand(time(NULL));
int a,b[10000],p,l=0;
scanf("%d",&a);//输入冒泡数字量
for(int i=1;i<=a;i++)
{
b[i]=rand()%100;
}
printf("由于您已是vip,自动为您生成随机数:\n");
for(int i=1;i<=a;i++)
printf("%4d",b[i]);//%4d适合人看
printf("\n");
for(int j=1;j<=a;j++)//进行几轮冒泡
{
for(int k=1;k<=a;k++)
{
if(b[k]>b[k+1])
{
p=b[k];
b[k]=b[k+1];
b[k+1]=p;
}
}
printf("第%d轮:",j);
for(int k=1;k<=a;k++)
printf("%4d",b[k]);//%4d适合人看
printf("\n");
}
}
4.0:12/7洗牌程序以及全排列的另外一种思路
一.全排列
全排列想必大家已经不陌生了,在中我提供了一个较为简单的思路,现在我们用另外一个方式来写,两者的思维其实一样,但这个方法倾向于选择fa
先上题目
1.全排列
题目描述
输入一个数 N, 求 1到 N 的全排列。
输入格式
输入一个 N,N<12。
输出格式
输出 N 的全排列,每个数字占 4
个位置。
样例1
输入
3
输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
为方便我们顺便在末尾写个这个全排列的组合有多少种!!
不多说,一切都在代码里,干了!!!
cpp
//全排列递归
#include <stdio.h>
int table[1000]; //存放一维数组
int count=0; //记录一维数组的总数
void Change(int &a,int &b) //将a和b进行交换
{
int temp=a;
a=b;
b=temp;
}
void DispTable(int a) //在屏幕上输出当前一维数组,函数中的a表示元素个数
{
int i;
for(i=0;i<=a;i++) //输出
printf("%d ",table[i]);
printf("\n");
}
void Tab(int table[],int a,int b) //从a到b进行值的交换
{
int i;
if(a==b) //交换到最后一个
{
DispTable(b); //输出当前一维数组
count++; //一维数组总数加1
}
else
{
for(i=a;i<=b;i++) //从a到b进行循环
{
Change(table[a],table[i]); //两两交换
Tab(table,a+1,b); //递归调用到下一层,重复进行交换
Change(table[a],table[i]); //复原交换数
}
}
}
int main()
{
int i,n;
scanf("%d",&n);
for(i=0;i<n;i++) //为一维数组赋初值
table[i]=i+1;
Tab(table,0,n-1); //在0~n-1之间进行值的交换
printf("%d\n",count);
return 0;
}
为了确保大家看得懂,这里举几个样例(非代码,仅用于解说)
//当n=4
Tab(table,0,3);
for(i=a;i<=b;i++) //从a到b进行循环
{
Change(table[a],table[i]); //两两交换
Tab(table,a+1,b); //递归调用到下一层,重复进行交换
Change(table[a],table[i]); //复原交换数
}
当i=0;
Change(table[0],table[0]); //两两交换
Tab(table,1,3); //递归调用到下一层,重复进行交换
Change(table[0],table[0]); //复原交换数
当i=1;
Change(table[0],table[1]); //两两交换
Tab(table,1,3); //递归调用到下一层,重复进行交换
Change(table[0],table[1]); //复原交换数
当i=2;
Change(table[0],table[2]); //两两交换
Tab(table,1,3); //递归调用到下一层,重复进行交换
Change(table[0],table[2]); //复原交换数
当i=3;
Change(table[0],table[3]); //两两交换
Tab(table,1,3); //递归调用到下一层,重复进行交换
Change(table[0],table[3]); //复原交换数
二、洗牌程序
由此我们可以写出一个类似的洗牌程序
cpp
/洗牌程序//1000ms延迟
#include <stdio.h>//
#include <stdlib.h>
#include <time.h>//随机数的头文件
#include<windows.h>//Sleep函数的头文件
void jh(int &x,int &y)//交换函数
{
int temp=x;
x=y;
y=temp;
}
int rand1(int x,int y) // 产生x---y之间的随机数
{
srand(time(NULL)); //随机函数初始化
return rand()%(y-x+1)+x; //返回一个x-y之间的数,y-x求出相差,5-3为2,共3个数,故生成%3数为0,1,2,加上3正好在3-5之间
}
int main()
{
int a[10]={0};
for(int i=0;i<10;i++)
a[i]=i;
for(int j=1;j<=20;j++)//直接生成20组
{
for(int i=9;i>=1;i--)//从后面开始,观察rand1就知道为什么从后面开始
jh(a[i],a[rand1(0,i)]);//将最后一个数与含有本身的任意一个位置交换,
for(int i=0;i<10;i++)//打印出来
printf("%d ",a[i]);
printf("\n");
Sleep(1000);//1000ms的延迟,这是为了使时间种子大一些,使生成的随机数不会出现相同的情况!!
}
return 0;
}
更多补充待续.....