/*Kaprekar映射:将数字按降序和升序排序减法;寻找周期。编译为:gcc-std=gnu99-g-O2;修改BASE以用于2到62范围内的不同基数*/#定义BASE 10#包括#包括#包括#包括#包括#包括#包括#包括#包括#定义NORETURN __attribute__((__NORETURN__))#定义PRINTF_FORMAT(X,Y)__attribute__((__FORMAT__(__PRINTF__,X,Y,))#定义未使用的__attribute__((__UNUSED__))#定义MALLOC_LIKE __attribute__((__MALLOC__))/*程序的名称(由util_init填写)*/static const char*program_name=“(未调用util_init)”;/*util_init-初始化给定argc和argv的实用程序函数:填写program_name*/静态空隙util_init(int argc未使用,char**argv){if(argv[0]==空){program_name=“(无可用程序名)”;}其他{程序名=strrchr(argv[0],'/');if(程序名!=空)程序名++;其他的程序名=argv[0];}}/*die-打印错误消息,前面加上“program_name:error:”后跟换行符,然后退出并返回错误状态*/静态NORETURN PRINTF_FORMAT(1,2)无效die(const char*格式,…){va_list参数;/*在写入错误消息时,我们不在此处检查错误,因为如果我们发现了一个,我们就无能为力了*/fprintf(stderr,“%s:错误:”,程序名);va_start(参数,格式);vfprintf(标准错误,格式,参数);putc('\n',stderr);va_end(参数);退出(exit_FAILURE);}/*恐慌&打印一个永远不会发生的错误并退出*/静态NORETURN PRINTF_FORMAT(1,2)无效恐慌(const char*格式,…){va_list参数;/*在写入错误消息时,我们不在此处检查错误,因为如果我们发现了一个,我们就无能为力了*/fprintf(stderr,“%s:panic(should never happen):”,程序名);va_start(参数,格式);vfprintf(标准错误,格式,参数);putc('\n',stderr);va_end(参数);退出(exit_FAILURE);}/*xvfprintf-打印某些内容(作为vfprintf,但带有文件名参数错误消息),检查错误*/静态PRINTF_FORMAT(3,0)无效xvfprintf(FILE*流,const char*文件名,const char*格式,va_list参数){int ret;ret=vfprintf(流、格式、参数);如果(ret<0)die(“写入%s:%s”,文件名,strerror(errno));}/*xprintf-打印内容(作为printf),检查错误*/静态PRINTF_FORMAT(1,2)无效xprintf(常量字符*格式,…){va_list参数;va_start(参数,格式);xvfprintf(标准输出,“标准输出”,格式,参数);va_end(参数);}/*xputc-打印字符(作为putc,但带有文件名参数错误消息),检查错误*/静态空隙xputc(int c,FILE*流,const char*文件名){if(putc(c,流)!=c)die(“%s:写入文件时出错:%s”,文件名,strerror(errno));}/*xflush-刷新流(作为fflush,但带有文件名参数错误消息),检查错误*/静态空隙xflush(文件*流,常量字符*文件名){fflush(溪流);if(费罗(流))die(“%s:写入文件时出错:%s”,文件名,strerror(errno));}/*xmlloc—分配内存,检查错误*/静态MALLOC_LIKE无效*xmalloc(size_t大小){无效*tmp;tmp=malloc(大小);如果(tmp==空)die(“malloc内存不足(%zu)”,大小);返回tmp;}/*xrealloc-重新分配内存,检查错误*/静态MALLOC_LIKE无效*xrealloc(void*buf,size_t size){无效*tmp;tmp=实际值(buf,大小);如果(tmp==空)die(“realloc内存不足(%zu)”,大小);返回tmp;}/*算术溢出-给出“算术溢出”错误*/静态NORETURN空隙算术溢出(void){die(“算术溢出”);}/*size_mul-安全地乘以size_t值*/静态size_tsize_mul(大小_大小1,大小_大小2){size_t ret=尺寸1*尺寸2;if(__builtin_expect((size1|size2)>=(((size_t)1)<<(CHAR_BIT*sizeof(size_t)/2)),0)) {if(ret/size2!=大小1)算术溢出();}返回ret;}/*size_muladd-安全计算size1*size2+size3*/静态size_tsize_muladd(大小_大小1,大小_大小2,大小_尺寸3){size_t ret=size_mul(size1,size2)+size3;if(ret<size3)算术溢出();返回ret;}/*xrealloc2—安全地重新分配(size1*size2)内存*/静态MALLOC_LIKE无效*xrealloc2(无效*buf,大小_大小1,大小_尺寸2){size_t大小=size_mul(size1,size2);return xrealloc(buf,大小);}/*xstrtoimax-读取intmax_t范围内的有符号整数,预期没有后续垃圾。第二个参数是对正在读取的内容,以获取错误消息*/静态intmax_txstrtoimax(常量字符*s,常量字符*desc){intmax_t ret;字符*endptr;错误号=0;ret=strtoimax(s,&endptr,0);if(errno!=0)die(“%s值“%s”:%s”,desc,s,strerror(errno));if(endptr==s|*endptr!=0)die(“%s值'%s'不是数字或有尾随垃圾邮件”,desc,s);返回ret;}/*打印基本数字*/静态空隙打印基础(int d){整数c;#如果基数<=10c=“0”+d;#elif基数<=36c=(d<10?'0'+d:'A'-10+d);#elif基底<=62c=(d<10?'0'+d:d<36?'A'-10+d:'A'-36+d);#其他#错误“无法打印超过62的底座”#结尾xputc(c,标准输出,“标准输出”);}/*数组IN_COUNTS统计数字中每个数字的数量长鼻梁。计算一次应用贴图的结果,然后将其以小元素的形式存储在数组OUT中,并将计数存储在OUT_COUNTS(输出_数量)。返回新的位数*/静态intone_iteration(int ndigits,const int in_counts[BASE],int out[ndigits],int out_counts[基数]){memset(out,0,ndigits*sizeof(int));memset(out_counts,0,BASE*sizeof(int));int pos=in_counts[0];for(int i=1;i<基数;i++){int npos=pos+in_counts[i];for(int j=pos;j<npos;j++){输出[j]+=i;输出[ndigits-1-j]-=i;}pos=非营利组织;}整数进位=0;对于(int i=0;i<ndigits;i++){/*该值始终在[-BASE,BASE-1]范围内*/int j=输出[i]+进位;如果(j<0){进位=-1;j+=基础;}其他的进位=0;输出[i]=j;out_counts[j]++;}if(进位!=0)恐慌(“迭代结束时进位”);while(out[ndigits-1]==0&&ndigits>1){ndigits--;out_counts[0]--;}返回ndigits;}/*数组IN_COUNTS统计数字中每个数字的数量NDIGITS是循环中的一个成员。确定的长度循环及其最小元素,并调用cycle_FUNC*/静态空隙检查周期(int ndigits,const int in_counts[BASE],void cycle_func(int cfn数字,整数cycle_length,const int循环计数[BASE],const int cycle_digits[ndigits])){int omin[ndigits],out[ndigitis];int c0[BASE],c1[BASE[基],cmin[基];memcpy(c0,in_counts,BASE*sizeof(int));整数i;对于(i=1;;i++){int n=一个迭代(ndigits,c0,out,c1);if(n!=非整数)恐慌(“数字在循环中下降”);bool new_min=真;如果(i>1){对于(int j=0;j<ndigits;j++){if(输出[ndigits-1-j]<输入[ndigit-1-j])断裂;if(out[ndigits-1-j]>omin[ndigit-1-j]){new_min=假;断裂;}}}if(新分钟){memcpy(omin,out,ndigits*sizeof(int));memcpy(cmin,c1,BASE*sizeof(int));}if(memcmp(in_counts,c1,BASE*sizeof(int))==0)断裂;memcpy(c0,c1,BASE*大小(int));}cycle_func(ndigits,i,cmin,omin);}/*数组IN_COUNTS统计数字中每个数字的数量长鼻梁。迭代贴图,直到一个循环或一个更小的数字按已排序数字的字典顺序或总计,大于IN_COUNTS已达到位数;如果是循环,则调用cycle_FUNC。如果SMALLER_OK,在达到循环之前不要停止*/静态空隙iterate_one_input(int ndigits,const int in_counts[BASE],bool smaller_ok,void cycle_func(int cfn数字,int循环长度,const int循环计数[BASE],const int cycle_digits[ndigits])){输入输出[ndigits];int slow1[BASE],slow2[BASE',fast1[BAES],fast2[BACE];int sndigits=ndigits,fndigits=ndigit;memcpy(slow1,in_counts,BASE*sizeof(int));memcpy(fast1,in_counts,BASE*sizeof(int));而(1){整数c;c=一个迭代(fndigits,fast1,out,fast2);if(smaller_ok)fn数字=c;其他的{如果(c<fn数字)回报;for(int i=0;i<BASE;i++){if(fast2[i]<in_counts[i])断裂;如果(fast2[i]>in_counts[i])回报;}}sndigits=one_iteration(sndigits,slow1,out,slow2);c=一个迭代(fndigits,fast2,out,fast1);if(smaller_ok)fn数字=c;其他的{如果(c<fn数字)回报;for(int i=0;i<BASE;i++){if(fast1[i]<in_counts[i])断裂;如果(fast1[i]>in_counts[i])回报;}}if(memcmp(fast1,slow2,BASE*sizeof(int))==0){check_cycle(fndigits、fast1、cycle_func);回报;}c=一个迭代(fndigits,fast1,out,fast2);if(smaller_ok)fn数字=c;其他的{如果(c<f位)回报;for(int i=0;i<BASE;i++){if(fast2[i]<in_counts[i])断裂;如果(fast2[i]>in_counts[i])回报;}}sndigits=one_iteration(sndigits,slow2,out,slow1);c=一个迭代(fndigits,fast2,out,fast1);if(smaller_ok)fn数字=c;其他的{如果(c<fn数字)回报;for(int i=0;i<基数;i++){if(fast1[i]<in_counts[i])断裂;如果(fast1[i]>in_counts[i])回报;}}if(memcmp(fast1,slow1,BASE*sizeof(int))==0){check_cycle(fn数字、fast1、cycle_func);回报;}}}静态bool ignore_13=假;结构循环{int个数字;整数长度;int计数[BASE];找到int个最小值;结构循环*next;};静态大小_循环数,循环数;结构周期长度计数{整数长度;size_t计数;struct cycle_length_count*next;};静态结构循环长度计数*循环长度计数;#定义HASHSIZE 1000000静态结构循环*cycle_hash[HASHSIZE];/*数组CYCLE_COUNTS给出每个数字的最小值长度为cycle_length的循环的元素;最小元素的数字在CYCLE_digits中。如果还没有报告周期参见*/静态空隙report_ cycle_,整数cycle_length,const int循环计数[BASE],常量int cycle_digits[ndigits]){如果(ignore_13&&(cycle_length==1||cycle_length==3))回报;size_t散列值=0;hashval=hashval*31+ndigits;hashval=hashval*31+循环长度;对于(int j=0;j<基数;j++)hashval=hashval*31+循环计数[j];hashval%=哈希大小;for(结构循环*cl=cycle_hash[hashval];cl!=空&&cl->ndigits==ndigits;cl=cl->下一步){如果(cl->len==周期长度&&memcmp(cl->counts,cycle_counts,BASE*sizeof(int))==0)回报;}结构循环*cnew=xmalloc(sizeof(结构循环));cnew->ndigits=ndigits;cnew->len=周期长度;memcpy(cnew->counts,cycle_counts,BASE*sizeof(int));cnew->least_found=0;cnew->next=循环哈希[hashval];cycle_hash[hashval]=cnew;循环次数++;number_in_cycles+=周期长度;结构周期长度计数**p;for(p=&cycle_length_counts;*p!=NULL;p=&((*p)->next))如果((*p)->长度==周期长度){(*p)->计数++;断裂;}如果(*p==空){*p=xmalloc(sizeof(结构周期长度计数));(*p)->len=周期长度;(*p)->计数=1;}xprintf(“%d循环:”,循环长度);对于(int j=0;j<ndigits;j++)打印基础(循环数字[ndigits-1-j]);xprintf(“\n”);xflush(标准输出,“标准输出”);int c0[BASE],c1[BASE',digs[ndigits];memcpy(c0,cycle_counts,BASE*sizeof(int));for(int i=1;i<循环长度;i++){int n=一个迭代(ndigits,c0,digs,c1);if(n!=非整数)恐慌(“数字在循环中下降”);xprintf(“%d-cycle-next:”,cycle_length);对于(int j=0;j<ndigits;j++)打印基础(digs[ndigits-1-j]);xprintf(“\n”);xflush(标准输出,“标准输出”);memcpy(c0,c1,BASE*大小(int));}}静态int current_in_counts[BASE];静态int current_ndigits;/*数组CYCLE_COUNTS给出每个数字的最小值长度为cycle_length的循环的元素;最小元素的数字在CYCLE_digits中。报告达到此值的最小数量循环(如果尚未完成)*/静态空隙report_least_reaching_cycle_if_new(int个ndigits,整数cycle_length,const int循环计数[BASE],常量int cycle_digits[ndigits]){if(ndigits<当前数字)回报;size_t散列值=0;hashval=hashval*31+ndigits;hashval=hashval*31+循环长度;对于(int j=0;j<基数;j++)hashval=hashval*31+循环计数[j];hashval%=哈希大小;for(结构循环*cl=cycle_hash[hashval];氯!=空&&cl->ndigits==ndigits;cl=cl->下一步){如果(cl->len==循环长度&&memcmp(cl->counts,cycle_counts,BASE*sizeof(int))==0){if(cl->least_found)回报;cl->least_found=1;循环次数--;xprintf(“最小值:”);对于(int j=1;j<基数;j++)if(当前计数[j]){打印基础(j);当前_计数[j]--;断裂;}对于(int j=0;j<基数;j++)while(current_in_counts[j]){打印基础(j);current_in_counts[j]-;}xprintf(“%d”,周期长度);对于(int j=0;j<ndigits;j++)打印基础(循环数字[ndigits-1-j]);xprintf(“\n”);xflush(标准输出,“标准输出”);回报;}}恐慌(“达到新周期的最少数量”);}/*只需报告一个周期*/静态空隙just_report_cycle(int个非整数,整数cycle_length,const int cycle_counts[BASE]未使用,常量int cycle_digits[ndigits]){xprintf(“%d循环:”,循环长度);对于(int j=0;j<ndigits;j++)打印基础(循环数字[ndigits-1-j]);xprintf(“\n”);xflush(标准输出,“标准输出”);}/*检查NDIGITS数字之间的循环,其中USED数字已用于NEXT以下的数字;COUNTS有计数,所以到目前为止,TOTAL是到目前为止的数字总数,DIFF是总数数量差异的绝对值数字d和BASE-1-d(对于1<=d<=BASE-2),不得以超过4*/静态空隙check_for_digits_recursive(int个ndigits,int个total,int个diff,已使用int,int next,int计数[BASE]){if((已使用==ndigits||next==BASE-1)&&((总计%(基数-1))!=0))回报;if(下一个==基数-1){counts[next]=ndigits-已使用;迭代输入(ndigits,counts,false,report_cycle_if_new);回报;}if(下一个<=((基数-1)/2+1)){int half=已使用;if((基数-1)%2==0&&下一个==((基数-1)/2+1))half-=计数[(BASE-1)/2];if(已使用+半-4>非整数)回报;}for(int i=ndigits-已使用;i>=0;i--){int ndiff=差异;if(下一个>(基数-1)/2){ndiff+=abs(i-计数[BASE-1-下一个]);如果(ndiff>4)继续;}计数[next]=i;check_for_digits_recursive(ndigits,总计+i*next,ndiff,使用+i,下一个+1,计数);}}/*检查NDIGITS数字之间的循环*/静态空隙check_for_digits(int个非整数){int计数[BASE];xprintf(“考虑%d位数字。\n”,ndigits);xflush(标准输出,“标准输出”);check_for_digits_recursive(ndigits,0,0,0,0,counts);if(!ignore_13){xprintf(“周期数%d%zu\n”,ndigits,Number_of_cycles);xprintf(“周期数%d%zu\n”,ndigits,周期数);}for(struct cycle_length_count*p=循环长度计数;p!=无效的;p=p->下一步){xprintf(“周期长度计数%d%d%zu\n”,ndigits,p->len,p->count);p->计数=0;}xflush(标准输出,“标准输出”);}/*找出达到每个NDIGITS数字周期的最小数字,其中USED数字已用于NEXT以下的数字;COUNTS有到目前为止的计数*/静态空隙find_least_sources_recursive(int个ndigits,已使用int个,int个next,int计数[BASE]){if(下一个==基数-1){counts[next]=ndigits-已使用;memcpy(current_in_counts,counts,BASE*sizeof(int));iterate_one_input(非整数,计数,true,报告_最近_访问_周期_新);回报;}for(int i=ndigits-已使用;i>=0;i-){计数[next]=i;find_least_sources_recursive(ndigits,used+i,next+1,counts);if(循环数==0)回报;}}/*找出达到每个NDIGITS数字周期的最小数字*/静态空隙find_least_sources(int个非整数){int计数[BASE];当前数字=ndigits;if(循环数==0)回报;如果(ndigits==1){memset(计数,0,BASE*sizeof(int));计数[0]=1;memcpy(current_in_counts,counts,BASE*sizeof(int));iterate_one_input(非整数,计数,true,报告_最近_访问_周期_新);if(循环数==0)回报;}for(int i=1;i<基数;i++)/*最小非零数字为i;有j个0*/对于(int j=ndigits-1;j>=0;j--){memset(计数,0,BASE*sizeof(int));计数[0]=j;如果(i==基础-1){计数[i]=ndigits-j;memcpy(current_in_counts,count,BASE*sizeof(int));iterate_one_input(非整数,计数,true,报告_最近_访问_周期_新);if(循环数==0)回报;}其他的for(int k=n位数-j;k>=1;k-){计数[i]=k;查找最小源递归(ndigits,j+k,i+1,counts);if(循环数==0)回报;}}}/*确定以NDIGITS开始的序列结果第一位为1,最后一位为D,另一位为数字为0*/静态空隙check_10d(int ndigits,int d){int计数[BASE]={0};计数[0]=ndigits-2;计数[1]=1;计数[d]++;iterate_one_input(ndigits,counts,true,just_report_cycle);}/*将映射应用于表示为int的值一次,返回结果为int*/静态intone_iteration_int(int值){int ndigits=0;int计数[BASE]={0};while(值!=0){int d=值%BASE;值/=基数;计数[d]++;ndigits++;}如果(ndigits==0){计数[0]++;ndigits++;}输入输出[ndigits];int out_counts[基数];ndigits=one_iteration(ndigits,counts,out,out_counts);int ret=0;for(int i=ndigits-1;i>=0;i--)ret=ret*基础+输出[i];返回ret;}/*查找以int表示的值的轨迹,报告(全部以十进制表示)立即图像,循环的第一个元素达到,前周期的长度和前周期+周期*/静态空隙trajectory_int(int值){静态int*trajective_array=NULL;静态size_t轨迹分配=0;int value_succ=one_iteration_int(值);if(轨迹分配<1){trajecty_alloc=16;trajectory_array=xrealloc2(trajective_array,trajective_alloc,sizeof(int));}trajective_array[0]=值;size_t计数=1;size_t周期长度=0;而(1){int s=one_iteration_int(轨迹数组[计数-1]);对于(size_t j=1;j<=计数;j++)如果(s==轨迹数组[count-j]){cycle_length=j;断裂;}if(周期长度)断裂;if(trajective_alloc<=计数){trajectory_alloc=size_muladd(trajective_alloc,2,16);trajectory_array=xrealloc2(trajective_array,trajective_alloc,sizeof(int));}trajective_array[计数++]=s;}xprintf(“%d%d%d%zu%zu\n”,值,值_succ,trajective_array[count-cycle_length],count-cycle_length,计数);xflush(标准输出,“标准输出”);}/*读取MIN到范围内的int参数ARG(description DESC)MAX包含在内*/静态intread_int_arg(常量字符*参数,常量字符*描述,int最小值,int最大值){intmax_t val=xstrtoimax(参数,描述);if(val<min|val>max)die(“%s值'%s'超出范围[%d,%d]”,desc,arg,min,max);返回值;}整数main(int argc,char**argv){util_init(argc,argv);int dig_min=1,dig_max=int_max/BASE;int个数字;bool compute_10d_trachicles=false;bool find_lest=false;bool compute_range_trajectories=false;int dval=0;int ret;while((ret=getopt(argc,argv,“iltm”))!=-1)开关(ret){案例“i”:ignore_13=真;断裂;案例“l”:find_lest=真;断裂;案例't':compute_10d_trachicles=真;断裂;案例'm':compute_range_trajectories=true;断裂;案例“?”:/*已打印错误消息*/退出(exit_FAILURE);违约:panic(“getopt返回%d错误”,ret);}if(ignore_13+find_lest+compute_10d_trachicles+compute_range_trachicles>1)die(“传递了不兼容的选项”);if(计算范围轨迹){int val_min=0;int val_max=基数;而(val_max<INT_max/BASE)val_max*=基础;最大值--;if(argc>optind){val_min=读取_ int_arg(argv[选项],“最小值”,最小值,最大值);optind++;}if(argc>optind){val_max=读取_ int_arg(argv[选项],“最大值”,最小值,最大值);optind++;}for(int i=val_min;i<=val_max;i++)trajective_int(i);退出(exit_SUCCESS);}if(计算10d轨迹){dig_min=2;if(argc>optind){dval=读取_ int _ arg(argv[选项],“最后一位”,0,基数-1);optind++;}}if(argc>optind){dig_min=read_int_arg(argv[optind],“最小位数”,数字最小值,数字最大值);optind++;}if(argc>optind){dig_max=read_int_arg(argv[optind],“最大位数”,数字最小值,数字最大值);optind++;}if(argc>optind)die(“游离命令行参数”);对于(ndigits=dig_min;ndigits<=dig_max;ndigit++){if(计算10d轨迹)check_10d(ndigits,dval);其他的{周期数=0;number_in_cycles=0;检查数字(ndigits);if(find_lest)查找最小源(ndigit);}}退出(exit_SUCCESS);}