1019 数字黑洞 (20 分)
给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字。一直重复这样做,我们很快会停在有“数字黑洞”之称的 6174,这个神奇的数字也叫 Kaprekar 常数。
例如,我们从6767开始,将得到
7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
… …
现给定任意 4 位正整数,请编写程序演示到达黑洞的过程。
输入格式:
输入给出一个 (0,10
4
) 区间内的正整数 N。
输出格式:
如果 N 的 4 位数字全相等,则在一行内输出 N - N = 0000;否则将计算的每一步在一行内输出,直到 6174 作为差出现,输出格式见样例。注意每个数字按 4 位数格式输出。
输入样例 1:
6767
输出样例 1:
7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
输入样例 2:
2222
输出样例 2:
2222 - 2222 = 0000
非常简单的一道题
#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<algorithm>
using namespace std;
bool cmp(int a, int b)
{
return a > b;
}
void to_array(int n, int num[])
{
for (int i = 0; i < 4; i++)
{
num[i] = n % 10;
n /= 10;
}
}
int to_number(int num[])
{
int sum = 0;
for (int i = 0; i < 4; i++)
{
sum = sum * 10 + num[i];
}
return sum;
}
int main()
{
int n, MIN, MAX;
scanf("%d", &n);
int num[5];
while (1)
{
to_array(n, num);
sort(num, num + 4);
MIN = to_number(num);
sort(num, num + 4, cmp);
MAX = to_number(num);
n = MAX - MIN;
printf("%04d - %04d = %04d\n", MAX, MIN, n);
if (n == 0 || n == 6174)break;
}
return 0;
}
最小公倍数和最大公约数
最大公约数(Greatest Common Divisor)可用欧几里得算法,及辗转相除法求得
//最大公约数
int gcd(int a, int b)
{
if (b == 0)return a;
else return gcd(b, a % b);
}
最小公倍数(Lowest Common Multiple)可在先求出最大公约数的情况下,将两数相乘再除以最大公约数求得
int lcm(int a, int b)
{
return a * b / gcd(a, b);
}
分数的化简及其四则运算
这部分也很简单,将分数视作一个结构体,成员包括分子和分母
//分数定义
struct Fraction
{
int up, down;
};
化简时的三项规定
1.若分母为负数,则上下同取相反数
2.分子为0,则分母为1
3.约分:求出分子绝对值和分母绝对值的最大公约数d,然后同除以d
//分数化简
Fraction reduction(Fraction result)
{
if (result.down < 0)
{
result.up = -result.up;
result.down = -result.down;
}
if (result.up == 0)
{
result.down = 1;
}
else
{
int d = gcd(abs(result.up), abs(result.down));
result.up /= d;
result.down /= d;
}
return result;
}
四则运算就是套公式
//分数加法
Fraction add(Fraction f1, Fraction f2)
{
Fraction result;
result.up = f1.up * f2.down + f2.up * f1.down;
result.down = f1.down * f2.down;
return reduction(result);
}
//分数减法
Fraction minu(Fraction f1, Fraction f2)
{
Fraction result;
result.up = f1.up * f2.down - f2.up * f1.down;
result.down = f1.down * f2.down;
return reduction(result);
}
//分数乘法
Fraction multi(Fraction f1, Fraction f2)
{
Fraction result;
result.up = f1.up * f2.up;
result.down = f1.down * f2.down;
return reduction(result);
}
//分数除法
Fraction divide(Fraction f1, Fraction f2)
{
Fraction result;
result.up = f1.up * f2.down;
result.down = f1.down * f2.up;
return reduction(result);
}
分数输出
1.输出前先化简
2.若分母为1,则只输出分子
3.假分数以带分数方式输出,整数部分为r.up/r.down,分子部分为abs(r.up)%r.down
4.真分数按原样输出
//分数输出
void showResult(Fraction r)
{
r = reduction(r);
if (r.down == 1)printf("%d", r.up);
else if (abs(r.up) > r.down)
{
printf("%d %d/%d", r.up / r.down, abs(r.up) % r.down, r.down);
}
else
{
printf("%d/%d", r.up, r.down);
}
}
素数
素数的判断
bool isPrime(int n)
{
if (n <= 1)return false;
int sqr = (int)sqrt(1.0 * n);
for (int i = 2; i <= sqr; i++)
{
if (n % i == 0)return false;
}
return true;
}
素数表的获取
可以使用埃式筛法,即Eratosthenes筛法。算法从小到大枚举所有数,对每一个素数,筛去他的所有倍数,剩下的就是素数。
以下是求解100以内素数的程序
const int maxn = 101;
int prime[maxn], pNum = 0;//素数数组和素数个数
bool p[maxn] = { 0 };//记录是否为素数,true表示是素数
void Find_Prime()
{
for (int i = 2; i < maxn; i++)
{
if (p[i] == false)//若i是素数
{
prime[pNum++] = i;//把素数i放入prime数组中
for (int j = i + i; j < maxn; j += i)
{
p[j] = true;//筛去i的所有倍数
}
}
}
}
运行结果
质因子分解
先建一个结构体数组,用于存放质因子
struct factor
{
int x, cnt;//x表示质因子,cnt表示个数
}fac[10];
判断过程:
1.枚举1~sqrt(n)范围内的所有质因子p,判断p是否是n的因子
如果p是n的因子,那么给fac数组增加质因子p,并初始化其个数为0,只给将n不断除以p,若能整除则cnt++,直到不能整除
如果不是则直接跳过
2.如果在上面步骤后n仍然大于1,说明n尤其仅有一个大于sqrt(n)的质因子么有可能是n本身,这时将这个质因子加入数组,并令其个数为1
bool isPrime(int n)
{
if (n <= 1)return false;
int sqr = (int)sqrt(1.0 * n);
for (int i = 2; i <= sqr; i++)
{
if (n % i == 0)return false;
}
return true;
}
const int maxn = 101;
int prime[maxn], pNum = 0;//素数数组和素数个数
bool p[maxn] = { 0 };//记录是否为素数,true表示是素数
void Find_Prime()
{
for (int i = 2; i < maxn; i++)
{
if (p[i] == false)//若i是素数
{
prime[pNum++] = i;//把素数i放入prime数组中
for (int j = i + i; j < maxn; j += i)
{
p[j] = true;//筛去i的所有倍数
}
}
}
}
struct factor
{
int x, cnt;//x表示质因子,cnt表示个数
}fac[10];
int main()
{
int n,num=0;//num表示不同质因子的个数
scanf("%d", &n);
Find_Prime();
if (n == 1)printf("1=1\n");//若n为1则直接输出
else
{
int sqr = (int)sqrt(1.0 * n);
for (int i = 0; i < pNum && prime[i] <= sqr; i++)
{
if (n % prime[i] == 0)//若prime[i]是n的因子
{
fac[num].x = prime[i];//记录该因子
fac[num].cnt = 0;
while (n % prime[i] == 0)
{
fac[num].cnt++;
n /= prime[i];
}//计算该因子的次数
num++;//不同质因子的个数+1
}
if (n == 1)break;
}
if (n != 1)//若无法被sqrt(n)以内的质因子除尽
{
fac[num].x = n;
fac[num++].cnt = 1;
}
for (int i = 0; i < num; i++)//输出
{
if (i > 0)printf("*");
printf("%d", fac[i].x);
if (fac[i].cnt > 1)
{
printf("^%d", fac[i].cnt);
}
}
}
}
结果