CodeForces - 95B (dfs)
题目链接:http://codeforces.com/problemset/problem/95/B
题意:
给你一个数字,要你求出不小于它的最小的超级完美数。超级完美数的定义是:这个数字每一位都是4或者7,并且4的总位数要等于7的总位数。
思路:
我刚开始推算的思路是:要是这个数有奇数位,那么就只需要加一位,加了一个位数的话肯定是比原来的数要大的,就只需要求出加了一位之后的最小超级完美数,即前一半位数是4,后一半位数是7。如果是偶数位的话,先将这个数与当前位数的最大的超级完美数比较,即前一半7后一半4的那个数,如果这个数比当前位最大的超级完美数还要大,说明还要加两位,加位的答案就是前一半4后一半7。否则的话,就从当前位数最小的超级完美数开始遍历,找出最小的不小于它的超级完美数。(事实证明,前面的想法都是没问题的,问题就出在这里)因为超级完美数都是相等数量的4和相等数量的7组成的,所以我就想着字典序全排列的话,从小到大遍历过去判断就行了,但是这样子做是会超时的,因为字典序全排列这个过程时间消耗很大。改进的方法就是,不依次与超级完美数进行比较,而是直接处理当前这个数,将它变成符合要求的超级完美数。然后看了下别人写的,感觉这个dfs的写法挺好的,避免了我之前的一些重复操作。下面就给出我自己的TLE代码和别人用dfs写的AC代码吧。
代码:
1 /*————————————————————AC代码————————————————————*/ 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int maxn = 1e5 + 10; 6 int len; 7 char str[maxn]; 8 char ans[maxn]; 9 bool dfs(int pos, int sum1, int sum2, bool flag) //pos指当前位数,sum1指4的总个数,sum2指7的总个数,flag标识符 10 { 11 if(pos >= len) 12 return true; 13 if(flag) //前面有位数变大了,那么后面的数就按一半4一半7排列 14 { 15 for(int i = 0; i < sum1; i++) 16 ans[pos++] = '4'; 17 for(int i = 0; i < sum2; i++) 18 ans[pos++] = '7'; 19 return true; 20 } 21 if(sum1 && str[pos] <= '4') 22 { 23 if(dfs(pos + 1, sum1 - 1, sum2, str[pos] != '4')) //遍历到一个比4小的数,并且将这个位数的数变成4是可行的 24 { 25 ans[pos] = '4'; 26 return true; 27 } 28 } 29 if(sum2 && str[pos] <= '7') 30 { 31 if(dfs(pos + 1, sum1, sum2 - 1, str[pos] != '7')) //遍历到一个比7小的数,并且将这个位数的数变成7是可行的 32 { 33 ans[pos] = '7'; 34 return true; 35 } 36 } 37 return false; //没有比4和7小的数,说明当前位数不够,要加两位 38 } 39 40 int main() 41 { 42 cin >> str; 43 len = strlen(str); 44 if(len & 1 || !dfs(0, len / 2, len / 2, 0)) 45 { 46 if(len & 1) //奇数位加一位 47 len++; 48 else //dfs返回false加两位 49 len += 2; 50 //加位的话一半4一半7就行 51 int i; 52 for(i = 0; i < len / 2; i++) 53 ans[i] = '4'; 54 for(i ; i < len; i++) 55 ans[i] = '7'; 56 } 57 cout << ans << endl; 58 return 0; 59 }
1 /*————————————————————TLE代码————————————————————*/ 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 #include<cstring> 6 7 const int maxn = 1e5 + 10; 8 char num[maxn]; 9 char tmp[maxn]; 10 11 int main() 12 { 13 while(scanf("%s", num) != EOF) 14 { 15 int len = strlen(num); 16 if(len % 2) //奇数位的话,+1位,前一半是4,后一半是7 17 { 18 for(int i = 0; i < (len + 1) / 2; i++) 19 { 20 printf("4"); 21 } 22 for(int i = (len + 1) / 2; i < len + 1; i++) 23 { 24 printf("7"); 25 } 26 printf("\n"); 27 } 28 else 29 { 30 for(int i = 0; i < (len / 2); i++) 31 { 32 tmp[i] = '7'; 33 } 34 for(int i = (len / 2); i < len; i++) 35 { 36 tmp[i] = '4'; 37 } 38 //如果比当前位数情况下最大的超级完美数还要大,就要加两位 39 if(strcmp(num, tmp) == 1) 40 { 41 //加位前一半4,后一半7 42 for(int i = 0; i < ((len + 2) / 2); i++) 43 { 44 printf("4"); 45 } 46 for(int i = ((len + 2) / 2); i < len + 2; i++) 47 { 48 printf("7"); 49 } 50 printf("\n"); 51 } 52 else 53 { 54 //位数固定,4和7的数量固定,字典序全排列列举比较,找最小的不低于的,就从最小的开始 55 for(int i = 0; i < (len / 2); i++) 56 { 57 tmp[i] = '4'; 58 } 59 for(int i = (len / 2); i < len; i++) 60 { 61 tmp[i] = '7'; 62 } 63 if(strcmp(num, tmp) != 1) 64 { 65 for(int i = 0; i < len; i++) 66 printf("%c", tmp[i]); 67 printf("\n"); 68 } 69 else 70 { 71 while(std::next_permutation(tmp, tmp + len)) 72 { 73 if(strcmp(num, tmp) != 1) 74 { 75 for(int i = 0; i < len; i++) 76 printf("%c", tmp[i]); 77 printf("\n"); 78 break; 79 } 80 } 81 } 82 } 83 } 84 } 85 return 0; 86 }