算法竞赛入门经典:第五章 基础题目选解 5.7 6174问题

/*
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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值