算法竞赛入门经典:第五章 基础题目选解 5.7 6174问题
2015-08-11 11:10
531 查看
/* 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; }
相关文章推荐
- leetcode 233: Number of Digit One
- [JavaScript] Google Closure: 糟糕的JavaScript
- Linux电源管理(1)_整体架构
- 二级指针的使用
- iOS跳转界面时隐藏tabBar的方法:hidesBottomBarWhenPushed
- mysqldump参数之-A -B
- 算法竞赛入门经典:第五章 基础题目选解 5.6 数组模拟高精度乘法
- 最长公共子序列(动态规划)
- Servlet是否线程安全
- Erlang MQTT消息服务器
- sass 在线转换器
- 优秀书籍推荐
- Attribute xx is only used in API level xx and higher (current min is xx)的解决方法
- POJ 3264 Balanced Lineup
- Android studio .9图片造成的错误总结
- php实现可逆加密的方法
- Linux图形界面与字符界面切换
- GCD的使用与理解(2)
- oracle求每月第一天和最后一天
- Boost学习资源搜集