UVaLive 4868 Palindrometer (暴力 / 构造)
题意:
给定一个固定长度的字符串, 字符串是一个含有前导0的数字, 问这个数字加上多少能构成一个回文字符串。
分析:
其实这题有很多种方法, 方法12是我做完后看别人代码总结的, 方法3是我当时想的一种方法。
方法一:
最直观的想法,从这个数字开始枚举, 知道找到回文字符串为止。
注意 %0'length‘d 可以输出前导0 , 比如 %03d输出1的话就是 ”001“
另外代码需要注意效率, 不然容易超时。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int len; 4 bool pre(const char a[]){//判断是否回文串 5 for(int i = 0, j = len - 1; i < j; i++, j--){ 6 if(a[i] != a[j]) 7 return false; 8 } 9 return true; 10 } 11 int main(){ 12 char str[30]; 13 while(scanf("%s", str )){ 14 len = strlen(str); 15 16 if (len == 1) break; 17 18 int i = 0, n = atoi(str);//先将str转化为int 19 20 char print[50], buf[50]; 21 22 sprintf(print, "%%0%dd", len);//构造出“%0'长度'd”的字符串, 方便下面sprintf输出前导0 23 24 memcpy(buf,str,len);//可以将枚举数组设为buf, 就不用更改原来数组了 25 26 27 while(!pre(buf)){//枚举即可 28 i++; 29 sprintf(buf,print, n + i); 30 } 31 printf("%d\n", i); 32 33 } 34 }
方法二:
构造出最接近的回文串, 方法是从判断每一对回文, 如果高位大于低位, 低位更改为高位, 否则低位的前一位进一, 低位更改为高位。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int len; 4 int a[20]; 5 char s[20]; 6 void carry(){ 7 for(int i = len - 1; i >= 0; i --){ 8 if(a[i] >= 10){ 9 a[i-1] ++; 10 a[i] %= 10; 11 } 12 } 13 } 14 bool change(){ 15 for(int i = 0, j = len - 1; i < j; i++, j--){ 16 if(a[i] > a[j]){ 17 a[j] = a[i];//位置对应的高低位, 如果高位大于低位的, 后面直接更改为低位 18 }else if(a[j] > a[i]){ 19 a[j] = a[i];//否则 如果低位大于高位的, 低位的前一位++, 低位改为高位 20 a[j-1] ++; 21 carry(); 22 return true;//进位后要重新进行一次change(), 因为进位的可能是之前已经判断过的字符 23 } 24 } 25 return false; 26 } 27 int main(){ 28 while(scanf("%s", s)){ 29 len = strlen(s); 30 if(len == 1) break; 31 int n1, n2; 32 sscanf(s,"%d", &n1); 33 for(int i = 0; i < len; i++){ 34 a[i] = s[i] - '0'; 35 } 36 a[len] = 0; 37 while(change()); 38 n2 = 0; 39 for(int i = len - 1; i >=0;i--){ 40 n2 *= 10; 41 n2 += a[i]; 42 } 43 printf("%d\n", n2 - n1); 44 } 45 return 0; 46 }
方法三:
我自己的想法是判断最内层的非回文对, 如果高位大于低位, 那么低位以及低位之后的都更改为高位的回文,
否则的话, 偶数情况中间两个字符中较小的(同样大小取高位),奇数情况则直接取中间的数, 这个数字+1, 如果有进位先进位。
然后这个数字之后的所有数字都更改为与之对应的高位, 那么就是回文串。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n; 4 int len; 5 int main(){ 6 char s[20]; 7 while(scanf("%s", s)){ 8 int len = strlen(s); 9 int n1, n2; 10 sscanf(s,"%d",&n1); 11 12 if (len == 1){ 13 break; 14 } 15 int k = -1, i; 16 17 for(i = 0; i < len/2; i++){ 18 if(s[i] != s[len - i - 1]){ 19 k = i; 20 } 21 } 22 if(k == -1){ 23 printf("0\n"); 24 continue; 25 } 26 // printf("k : %d\n", k); 27 if( s[len - k - 1] < s[k]){//如果最里面不同一对的低位 小于高位 改这一对的后面 28 s[len-k-1] = s[k]; 29 int cnt = 0; 30 for(int i = len-k; i < len; i++){ 31 s[i] = s[len - i - 1]; 32 } 33 } 34 else // 只能改中间 35 { 36 int mid; 37 if(len % 2 == 0){//偶数情况哪个小要哪个 38 mid = s[len/2-1] <= s[len/2] ? len/2-1: len/2; 39 } 40 else{ 41 mid = len/2; 42 } 43 44 s[mid]++; 45 for(int i = mid; i >=0 ; i--){ 46 if(s[i] > '9'){ 47 s[i] = '0'; 48 s[i-1]++; 49 } 50 } 51 for(int i = mid+1; i < len; i++){ 52 s[i] = s[len-i-1]; 53 } 54 55 } 56 sscanf(s,"%d",&n2); 57 printf("%d\n", n2 - n1); 58 59 } 60 return 0; 61 }