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 }

 

posted @ 2017-07-28 09:44  Neord  阅读(145)  评论(0编辑  收藏  举报