对于数学黑洞相似问题的求解
对于数学黑洞,无论怎样设值,在规定的处理法则下,最终都将得到固定的一个值,再也跳不出去了,就像宇宙中的黑洞可以将任何物质,以及运行速度最快的光牢牢吸住,不使它们逃脱一样。
6174问题
即卡普雷卡尔(Kaprekar)常数
假设你有一个各位数字互不相同的四位数,把所有数字从大到小排序后得到a,从小到大排序后得到b,然后用a-b替换掉原来这个数,并且继续操作。例如,从1234出发,依次可以得到4321-1234=3087,8730-378=8352,8532-2358=6174。有趣的是,7641-1467=6174,回到它自己。
请输入一个n位数,输出操作序列,直到出现循环(即新的数曾今得到过)。输入保证再循环前最多只会产生1000个整数。
样例输入:1234
样例输出:1234->3087->8352->6174->6174
【分析】
两个问题摆在我们面前:如何得到下一个数?如何检查这个数是否已经出现过?让我们用两个函数一一解决。
#include <iostream>
using namespace std;
int num[2000];
int count = 0;
int get_next(int x)
{
int a = 0;
int b = 0;
int n = 0;
char s[10];//转换成字符串
sprintf(s, "%d", x);
n = strlen(s);
for(int i=0; i<n; i++)//冒泡排序
for(int j=i+1; j<n; j++){
if(s[i] > s[j]){
char t = s[i];
s[i] = s[j];
s[j] = t;
}
}
sscanf(s, "%d", &b);//在最小的排列
for(i=0; i<n/2; i++){//逆置
char t = s[i];
s[i] = s[n-1-i];
s[n-1-i] = t;
}
sscanf(s, "%d", &a);//最大的排列
return a - b;
}
int main()
{
cin >> num[0];
cout << num[0];
count = 1;
//这种模式可以解决大多数类似数学黑洞的问题
while(1)
{
num[count] = get_next(num[count-1]);
cout << " -> " << num[count];
int found = 0;
for(int i=0; i<count; i++){
if(num[i] == num[count]){
found = 1;
break;
}
}
if(1 == found) break;
count++;
}
cout << endl;
return 0;
}
其实达到卡普雷卡尔黑洞6174最多需要14个步骤
123问题
即西西弗斯串
设定一个任意数字串,数出这个数中的偶数个数,奇数个数,及这个数中所包含的所有位数的总数,
例如:1234567890,
数出该数数字中的偶数个数,在本例中总共有 5 个。
数出该数数字中的奇数个数,在本例中总共有 5 个。
数出该数数字的总个数,本例中为 10 个。
将答案按 “偶-奇-总” 的位序,重新组合为:5510。
重复以上动作可得到新数:134。
继续运算可得到新数:123。
结论:对数1234567890,按上述算法,最后必得出123的结果,我们可以用计算机写出程序,测试出对任意一个数经有限次重复后都会是123。换言之,任何数的最终结果都无法逃逸123黑洞。
#include <iostream>
using namespace std;
char num[1000];
char temp[100];
int count = 0;
int get_next(int x)
{
int even = 0;
int odd = 0;
int n = 0;
sprintf(temp, "%d", x);
n = strlen(temp);
//sprintf的执行会刷新后赋值,所以n的值总是对的
for(int i=0; i<n; i++){
if((temp[i] - '0') % 2 == 0) even++;
else if((temp[i] - '0') % 2 == 1) odd++;
}
sprintf(temp, "%d%d%d", even, odd, n);
sscanf(temp, "%d", &n);
return n;
}
int main()
{
int even = 0;
int odd = 0;
int n = 0;
cin >> num;
cout << num;
n = strlen(num);
//由于第一个输入的数可能非常大,所以先用字符串处理第一个数
for(int i=0; i<n; i++){
if((num[i] - '0') % 2 == 0) even++;
else if((num[i] - '0') % 2 == 1) odd++;
}
sprintf(num, "%d%d%d", even, odd, n);
sscanf(num, "%d", &count);
while(1)
{
cout << " -> " << count;
if(count == 123) break;
count = get_next(count);
}
cout << endl;
return 0;
}
冰雹猜想
角谷猜想
该猜想由日本数学家角谷静夫发现,是指对於每一个正整数,如果它是奇数,则对它乘 3 再加 1,如果它是偶数,则对它除以 2,如此循环,最终都能够得到 1。
如n = 6,根据上述公式,得出 6→3→10→5→16→8→4→2→1。(步骤中最大的数是16,共有7个步骤)
#include <iostream>
using namespace std;
#define MAX 1000
int num[MAX];
int max = 0;
int p = 0;
int main()
{
int i = 0;
cin >> num[0];
cout << num[0];
for(i=0; i<MAX; i++){
if(1 == num[i]) break;
if(max < num[i]){
max = num[i];
p = i;
}
if(num[i] % 2 == 0) num[i+1] = num[i] / 2;
else if(num[i] % 2 == 1) num[i+1] = num[i] * 3 + 1;
cout << "->" << num[i+1];
}
cout << endl << endl;
cout << "一共有" << i << "个步骤" << endl;
cout << "经过" << p << "次变换达到最大值" << max << endl;
return 0;
}
自幂数
自幂数是指一个 n 位数,它的每个位上的数字的 n 次幂之和等于它本身。
n为1时,自幂数称为独身数。显然,0,1,2,3,4,5,6,7,8,9都是自幂数。
n为2时,没有自幂数。
n为3时,自幂数称为水仙花数,有4个:153,370,371,407;
n为4时,自幂数称为四叶玫瑰数,共有3个:1634,8208,9474;
n为5时,自幂数称为五角星数,共有3个:54748,92727,93084;
n为6时,自幂数称为六合数, 只有1个:548834;
n为7时,自幂数称为北斗七星数, 共有4个:1741725,4210818,9800817,9926315;
n为8时,自幂数称为八仙数, 共有3个:24678050,24678051,88593477;
n为9时,自幂数称为九九重阳数,共有4个:146511208,472335975,534494836,912985153;
n为10时,自幂数称为十全十美数,只有1个:4679307774。
总共有88个自幂数,最大的自幂数是115132219018763992565095597973971522401。
现在输入一个整数,求出所有小于该整数的自幂数
#include <iostream>
#include <cmath>
using namespace std;
int table[10][10];
int selfLen(int num){
if(num <=0 ) return -1;
for(int i=0; num>0; i++){
num /= 10;
}
return i;
}
void selfNumber(int num)
{
int len = selfLen(num);
int sum = 0;
for(int i=num; i>0; i/=10){
sum += table[len][i%10];
//求每一位的n次幂的和
}
if(sum == num){
cout << num << endl;
}
}
int main()
{
int count = 0;
//建立一个表,方便查询,提高效率,如table[4][5]中存储的是5的4次方
for(int i=0; i<10; i++)
for(int j=0; j<10; j++){
table[i][j] = pow(j, i);
}
scanf("%d", &count);
for(i = 0; i < count; i++){
selfNumber(i);
}
return 0;
}
告辞