/*
6174问题:
一个各位数字互不相同的四位数,把所有数字从大到小排序后得到a,从小到大排序后得到b,然后用a-b替换原来的数,并且继续操作。
例如,从1234触发,依次可以得到4321 - 1234 = 3087,8730 - 378 = 8352,8352 - 2358 = 6174。7641 - 1467 = 6174,回到了它自己。
输入一个n位数,输出操作序列,直到出现循环(即新得到的数曾经得到过)。输入保证在循环之前最多只会产生1000个整数。
输入:1234
输出:1234->3087->8352->6174->6174
//思路:如何获取下一个数。用原数获取获取各个数位,然后采用快排排好,相减,产生下面两个数,循环终止条件是(前面非循环《=1000次,要产生循环)
*/
//新出现的数已经出现过,可以用一个哈希数组做减枝标记
/*
关键:
1 for(int j = iLen - 1 ; j > i ;j--),复习冒泡排序,n-1趟,从后向前排序
2 iMark[iCount] = get_next(iMark[iCount-1]);//注意变量。将程序化分成两部分:获取下一个数+循环。而排序使用字符数组的排序,采用冒泡排序。sscanf,sprintf
3 排序用字符串排,很新颖。sprintf(str,"%d",num);//int sprintf(char* buffer,const char* format,...),输出的缓冲区是字符串,返回值是写入的字符串数量
4 sscanf(str,"%d",&iMin);//int sscanf(const char* buffer,const char* format,..)输入从缓冲区中读,可以将buffer去掉看,因此用%d而不是%s
5 出现的比较用,当前数与之前所有数比较。if(iMark[k] == iMark[iCount])
*/
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
//复习冒泡排序,n-1趟,从后向前排序
#define MAXSIZE 1024
int iMarkCir[10000];
using namespace std;
void pro_6174(int iNum)
{
iMarkCir[iNum] = 1;
printf("%d->",iNum);
static int iCount = 0;//计数器,超过1000,直接退出
if(iCount >= 1000)
{
return;
}
int iArr[5];
int i = 0;
int iMarkDif[10] = {0};
//分解各位,从低位到高位
do{
iArr[i] = iNum % 10;
iNum /= 10;
if(!iMarkDif[iArr[i]])//没有重复
{
iMarkDif[iArr[i]] = 1;
}
else//重复,直接退出
{
return;
}
i++;
}while(iNum);
//排序
sort(iArr,iArr + 4);//从低到高排1234,注意各个位数不能相同也是判断条件
int iMax = 0;
int iRadius = 10;
for(int j = 3 ; j >= 0 ; j--)
{
iMax = iMax * iRadius + iArr[j];
}
//获取小数
int iMin = 0;
for(int k = 0 ; k < 4 ; k++)
{
iMin = iMin * iRadius + iArr[k];
}
//产生新的数
int iNewNum = iMax - iMin;
if(iMarkCir[iNewNum])
{
printf("%d",iNewNum);
return;//说明已经出现过,直接退出
}
else//没出现过,递归调用
{
iMarkCir[iNewNum] = 1;
pro_6174(iNewNum);
}
}
//将程序化分成两部分:获取下一个数+循环。而排序使用字符数组的排序,采用冒泡排序。sscanf,sprintf
int get_next(int num)
{
int iMax,iMin;
char str[MAXSIZE];
sprintf(str,"%d",num);//int sprintf(char* buffer,const char* format,...),输出的缓冲区是字符串,返回值是写入的字符串数量
int iLen = strlen(str);
//求最小,1234,如前大于后则交换,采用标记flag
for(int i = 0 ; i < iLen - 1 ;i++)
{
bool isSeq = true;
//for(int j = i + 1 ; j < iLen ; j++)
for(int j = iLen - 1 ; j > i ;j--)
{
if(str[j-1] > str[j])
{
char ch = str[j-1];
str[j-1] = str[j];
str[j] = ch;
isSeq = false;
}
}
if(isSeq)
{
break;
}
}
//sscanf(&iMin,"%s",str);
sscanf(str,"%d",&iMin);//int sscanf(const char* buffer,const char* format,..)输入从缓冲区中读,可以将buffer去掉看,因此用%d而不是%s
//求最大值用逆序
for(int k = 0; k < iLen/2; k++)
{
char ch = str[k];
str[k] = str[iLen-1-k];
str[iLen-1-k] = ch;
}
//sscanf(&iMax,"%s",str);
sscanf(str,"%d",&iMax);
return (iMax - iMin);
}
void pro_6174_2(int iNum)
{
printf("%d",iNum);
int iMark[2000];
int iCount = 0;
iMark[iCount++] = iNum;
bool isCir = false;
for( ; ; )
{
iMark[iCount] = get_next(iMark[iCount-1]);//注意变量
printf("->%d",iMark[iCount]);
for(int k = 0 ; k < iCount ; k++)//当前数之前的所有数与这个数比较,是否已经出现过
{
if(iMark[k] == iMark[iCount])
{
isCir = true;
break;
}
}
if(isCir)
{
break;
}
iCount++;
}
printf("\n");
}
int main(int argc,char* argv[])
{
int iNum;
memset(iMarkCir,0,sizeof(iMarkCir));
scanf("%d",&iNum);
//pro_6174(iNum);
pro_6174_2(iNum);
system("pause");
return 0;
}
算法竞赛入门经典:第五章 基础题目选解 5.7 6174问题
最新推荐文章于 2020-09-12 10:57:17 发布