题目描述:
如果一个数正着读和反着读一样大,则这个数叫做回文数,例如121是回文数,123454321是回文数。
现给定一个正整数x,输出一个回文数y,要求y > x,并且组成x的所有数字之和与组成y的所有数字之和相等,以及y > x。
x在10^1000以内,因为数字较大,我们用字符串作为输入和输出。
如果无解,请输出Impossible。如果有多个y,输出最小的那个。
例如:
输入919,输出14941
输入1,输出Impossible
解题思路:
题目的意思是给定一个1到10^1000次以内的正整数x,求大于x且是回文的最小y,并且x与y的各位数字之和相等。回文数有如下性质:
(1)如果回文数各位之和是奇数,那么这个回文数的位数一定为奇数;
(2)设回文数的位数为w,当回文数的各位数字之和sum>=2时:
当sum为偶数的话,这个回文数的位数w可以为大于等于k的任意数(k为sum/9对上取整);
当sum为奇数的话,这个回文数的位数w可以为大于等于k的任意奇数(k为sum/9对上取整);
(3)给定各位之和sum 和 位数 w,且sum和w满足(2),那么我们可以求得各位之和为sum,位数为w的最小回文数和最大回文数,方法如下:
最小回文数:由外向内枚举各位数字,枚举从小到大进行,注意最高位从1开始而不是从0开始枚举;
最大回文数:由外向内枚举各位数字,枚举从大到小进行;
复杂度为O(w)
通过上面的性质,得出下面的方法:
string palindrom (string a){//返回值为所求的回文数 sum为各位数字之和,w字符串a的长度即位数 如果各位数字之和小于等于1,返回 Impossible; //一位数字单独处理 if(w为1){ if(sum为奇数) 返回各位数字之和为sum,位数为3的最小回文; else if(sum为偶数) 返回各位数字之和为sum,位数为2的最小回文; } //各位数字之和sum>=2,位数>=2 if(sum为奇数){//和为奇数,那么所求的回文位数也得是奇数 if(字符串a的位数w为偶数) 返回 位数为字符串位数+1,各位数字之和为sum的最小回文; else if(字符串a位数w为奇数){ if(字符串大于等于sum和w都相同的回文数的最大值) 返回位数为字符串位数+2(确保位数是奇数),各位数字之和为sum的最小回文数; else 通过getNear(sum,a,b)求得大于a的最小回文b } }else if(sum为偶数){//和为偶数 if(字符串大于等于sum和w都相同的回文数的最大值) 返回位数为字符串位数+1,各位数字之和为sum的最小回文; else 通过getNear(sum,a,b)求得大于a的最小回文b } }
getNear(sum,a,b)描述:
根据字符串a的前半部分构造回文b的前半部分:
如果恰好够造成的回文b的前半部分与a的前半部分一样:
如果回文b的后半部分大于a的后半部分:
那么这个回文b即为所求;
例如:a=1234123 ,根据a的前半部分构造出来的b=1234321,那么b即为所求;
如果回文b的后半部分小于等于a的后半部分:
那么需要找到以一个可+1的数位,然后对此位数字加1,然后内部数位重新够造成最小回文,得所求;
(由于是内部数字,所以这个内部最小回文的第一位可以是0);
第一个可+1数位为:本位数字<9,且内部数字之和大于等于2;
例如:a=1324312 ,根据a的前半部分构造出来的b=1324231,
由于b的后半部分小于a的后半部分, 那么在b中需要找到以一个可+1的数位,
第三位数字2满足条件,所以对其+1,然后内部数字够造成最小回文,结果b=1332331;
如果构造成的回文b的前半部分中有个数字比a中对应数字大:
那么,这个b即为所求;
例如a=1234444,当在构造b的前半部分的第三位时,b=12___21, 如果第3个数字取3的话,
那么剩余的内部数字之和为10,剩余内部位数为1,内部不能再继续构造,
所以第三位取4>3,则b=1248421即为所求;
如果构造成的回文b的前半部分中有个数字比a中对应数字小:
那么,同样需要向前找到第一个可+1位,对其加1,然后内部够造成最小回文,得所求;
例如:a=399212,当根据a的前半部分构造回文b的时候,第三位时:b=39__93,此时a的第三位是9,
但是b剩余内部数字之和为2,所以最大是1<9,
此时找到b的第一个可+1位为第一位,对其加1,然后内部够造成最小回文,那么b=409904
同样次过程的复杂度也是O(w),那么整个算法的复杂度是O(w)代码见http://blog.csdn.net/xhu_eternalcc/article/details/18182639
码字画图不容易,有问题请评论,转载请标明出处。