题目:输入一序列的正实数和幂次(正整数)对,然后打印结果(具体的比这个精细)

这道题是关于大数计算的(大数求幂),从开始建立思路,到写代码、调式到最后被AC以及最终的优化,总共用了差不多一天的时间。开始AC时使用空间500K,时间37MS,最后一次AC空间400K,时间0MS,有很大提高。这主要归功于加大了每次的数据处理量,减少了重计算次数以及降低循环代码量。还有就是在使用了二分递归,避免了重复计算。不好的一点是代码量太大,并且使用了太多的变量。

不管怎么样,为这道题付出了很多想法,后来的一些大的优化主要来自对底层的深入理解,代码的整体实现粒度是很细的,阅读起来可能会有些困难,但很是值得推敲的,具体实现代码如下:

[cpp] view plain copy

 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. void add(char *s1, char *s2);
  5. char *multi(char *s1, char *s2);
  6. char *result(char *s, int n);
  7. int main(void) {
  8. char ch[100];
  9. char *res;
  10. int  num, np;
  11. char tem, *temp1, *temp2;
  12. char *chp;
  13. while ( scanf("%s%d", ch, &num) != EOF ) {
  14. chp = ch + strspn(ch, "0");           // 去掉前导0
  15. temp1 = &ch[strlen(ch)-1];
  16. if ( (temp2 = strchr(ch, '.')) != NULL ) {  // 如果有小数点
  17. while ( *temp1 == '0' )  // 去掉小数末尾的0
  18. *temp1-- = 0;
  19. np  = strlen(temp2) - 1;
  20. np *= num;                  // 小数位的num倍是最终结果的小数位数
  21. memmove(temp2, temp2+1, strlen(temp2));  // 去掉小数点
  22. }
  23. else
  24. np = 0;             // 整数
  25. res   = result(chp, num);
  26. //        printf("res: %s\n", res);
  27. temp1 = res + strspn(res, "0");
  28. temp2 = &res[strlen(res) - np];     // 定位小数点
  29. if ( temp1 >= temp2 && np != 0 )   // 如果结果小于1
  30. printf("%c%s\n", '.', temp2);
  31. else if ( np == 0 )              // 如果是整数
  32. printf("%s\n", temp1 == temp2 ? 0 : temp1);
  33. else {
  34. tem   = *temp2;         // 将该放小数点位置的源字符保存
  35. *temp2++ = 0;           // 这里将源结果字符串断开,块式输出效率高
  36. printf("%s%c%c%s\n", temp1,
  37. '.', tem,
  38. *temp2 == 0 ? "" : temp2);
  39. }
  40. free(res);
  41. }
  42. return 0;
  43. }
  44. char *result(char *s, int n) {
  45. char *res, *ch1, *ch2;
  46. if ( n == 1 )
  47. return multi(s, "1");  // 返回统一类型的可被free掉的数据空间
  48. else if ( n == 2 )
  49. return multi(s, s);
  50. else if ( n > 2 ) {
  51. ch1 = result(s, n >> 1);  // 二分递归计算
  52. if ( n % 2 != 0 ) {
  53. ch2 = result(s, n - (n >> 1));
  54. res = multi(ch1, ch2);
  55. free(ch2);   // result函数返回值得释放掉
  56. }
  57. else   // 如果n是偶数,可避免重复计算
  58. res = multi(ch1, ch1);
  59. free(ch1);
  60. return res;
  61. }
  62. }
  63. char *multi(char *s1, char *s2) {
  64. int  i1, i2;
  65. char *ch1, *ch2, *cp1, *cp2, *cp3;
  66. char chp[18];
  67. int  i, j, num, dis;
  68. long long j1, j2, j3; // 加大每次计算量
  69. i1 = strlen(s1);
  70. i2 = strlen(s2);
  71. ch1 = (char *)malloc(i1 + i2 + 2);  // 1 bit '\0', 1 carry bit(reserved for)
  72. if ( strncmp(s2, "1", 1) == 0 && i2 == 1 ) {
  73. memcpy(ch1, s1, i1+1);
  74. return ch1;
  75. }
  76. ch2 = (char *)malloc(i1 + i2 + 1);  // 1 bit '\0'
  77. memset(ch1, '0', i1 + i2 + 2);
  78. ch1[i1+i2+1] = 0;
  79. i = i2;
  80. while ( i > 0 ) {
  81. if ( i >= 8 )           // 和j,每次各可处理8位
  82. dis = 8;
  83. else
  84. dis = i;
  85. i -= dis;
  86. memset(ch2, '0', i1 + i2 + 1);  // ch2每次循环都可能被修改
  87. ch2[i1+i2] = 0;
  88. cp1 = &s1[i1];
  89. cp2 = &s2[i2];
  90. cp3 = &ch2[i1 + i];  //  i1+i2-(i2-i)=i1+i, 每次循环往左移动dis位,表示和记录进位
  91. memcpy(chp, cp2 - i2 + i, dis);
  92. chp[dis] = 0;
  93. j2     = atoi(chp);
  94. j = i1;
  95. while ( j > 0 ) {
  96. if ( j >= 8 )     // 最多8位迭代处理与j2相乘
  97. num = 8;
  98. else
  99. num = j;
  100. cp1 -= num;
  101. memcpy(chp, cp1, num);
  102. chp[num] = 0;
  103. j1       = atoi(chp);
  104. memcpy(chp, cp3, dis);  // cp3记录进位,最多有dis位
  105. chp[dis] = 0;
  106. j3     = atoi(chp);
  107. snprintf(chp, 18, "%lld", j1 * j2 + j3);
  108. j1 = strlen(chp);
  109. memcpy(cp3 -j1 + dis, chp, j1);     // 数据向右对齐
  110. cp3 -= num;  // 定位到下次计算进位可能占据空间的开头地址
  111. j -= num;
  112. }
  113. add(ch1, ch2);   // 将新的计算结果与前面的相加,最后可获得最后结果
  114. }
  115. free(ch2);
  116. return ch1;
  117. }
  118. void add(char *s1, char *s2) {
  119. char *cp1, *cp2, *cp3, *ch;
  120. char chp[18];
  121. int  num, n1, n2;
  122. long long i, j, k;
  123. s2 += strspn(s2, "0");
  124. n1  = strlen(s1);       // make sure n1 > n2
  125. if ( (n2  = strlen(s2)) == 0 )
  126. return;
  127. ch  = (char *)malloc(n1+1);
  128. memset(ch, '0', n1);
  129. ch[n1] = 0;
  130. cp1 = &s1[n1];
  131. cp2 = &s2[n2];
  132. cp3 = &ch[n1 - 1];
  133. while ( n2 > 0 ) {    // must validate enough memory
  134. if ( n2 >= 16 )
  135. num = 16;
  136. else
  137. num = n2;
  138. cp1 -= num;
  139. cp2 -= num;
  140. memcpy(chp, cp1, num);
  141. chp[num] = 0;
  142. i        = atoll(chp);
  143. memcpy(chp, cp2, num);
  144. chp[num] = 0;
  145. j        = atoll(chp);
  146. memcpy(chp, cp3, 1);
  147. chp[1] = 0;
  148. k      = atoll(chp);
  149. snprintf(chp, 18, "%lld", i + j + k);
  150. i = strlen(chp);
  151. cp3 -= i - 1;
  152. memcpy(cp3, chp, i);
  153. cp3 += i - 1 - num;
  154. n2 -= num;
  155. }
  156. memcpy(s1, ch, n1);
  157. free(ch);
  158. }

原文转自 http://blog.csdn.net/chiichen/article/details/6685858

原作者为 chiichen. 请尊重原作者版权

北大OJ 1001题的更多相关文章

  1. acm入门 杭电1001题 有关溢出的考虑

    最近在尝试做acm试题,刚刚是1001题就把我困住了,这是题目: Problem Description In this problem, your task is to calculate SUM( ...

  2. 【Java】深深跪了,OJ题目Java与C运行效率对比(附带清华北大OJ内存计算的对比)

    看了园友的评论之后,我也好奇清橙OJ是怎么计算内存占用的.重新测试的情况附在原文后边. -------------------------------------- 这是切割线 ----------- ...

  3. hdu 5288||2015多校联合第一场1001题

    pid=5288">http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a ar ...

  4. Sublime Text3 配置C++(附oj刷题常用模板)

    # 下载对应平台的sublime sublime最新版下载, 字体样式个人喜欢Consolas, 另附注册码: -– BEGIN LICENSE -– TwitterInc 200 User Lice ...

  5. 九度oj 1001 A+B for Matrices 2011年浙江大学计算机及软件工程研究生机试真题

    题目1001:A+B for Matrices 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:15235 解决:6172 题目描述: This time, you are supposed ...

  6. Leetcode OJ 刷题

    Valid Palindrome吐槽一下Leetcode上各种不定义标准的输入输出(只是面试时起码能够问一下输入输出格式...),此篇文章不是详细的题解,是自己刷LeetCode的一个笔记吧,尽管没有 ...

  7. 九度OJ做题记录 更新.....

    2015年1月7日 20:34:23  题目1007:奥运排序问题 有点意思,以后想另外方法快速做出来 2015年1月7日 21:03:56 有一个技巧就是,写了三个比较函数cmp1,cmp2,cmp ...

  8. 牛客OJ——[编程题]A+B和C__如何输入多组测试数据(测试OK)

    几个要注意的地方: (1)Java OJ,必须将类名写成Main (2)关于如何输入多组测试数据,用二维数组去存储是一个方法,直接在while里面做也可以          但是如果  (3)关于整形 ...

  9. HDU 4738 Caocao's Bridges (2013杭州网络赛1001题,连通图,求桥)

    Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

随机推荐

  1. 通过url 下载文件

    1.问题简介 通过文件的url,将文件下载到本地.文件存储的位置为:tomcat服务器的文件夹(通过读取properties文件:可看:http://www.cnblogs.com/0201zcr/p ...

  2. iframe 的使用和登陆退出的实现——整个页面跳转

    iframe中如果只是页面跳转的话,我们依然只是部分的加载的了,为了实现整个页面的所有内容跳转,下面提供了整个页面跳转的方法. iframe例子 1.总的iframe页面(访问就访问这个)  all. ...

  3. Equinox P2的学习

    product.configuration 点击“Add按钮”并添加以下插件: org.eclipse.equinox.p2.ui org.eclipse.equinox.p2.ui.sdk org. ...

  4. 比较TFS与SVN,你必须知道的10点区别

      相比SVN,对于TFS的优点我有以下几点看法,供大家参考: 1. 总体比较: TFS是一个应用软件生命周期管理(ALM)软件,是一个软件研发平台产品,其功能覆盖了软件研发过程中的所有环节(包括源代 ...

  5. AWS国际版的Route 53和CloudFront

    注册AWS国际版账号后,却发现Route 53和CloudFront功能是无法使用的.于是提交了一个Service Request,得到的答复是这两个功能需要验证后才能激活. 在控制台中点击进入Rou ...

  6. OpenXml入门

    一. OpenXml简介: Open XML标准的简单介绍:Ecma Office Open XML(“Open XML”)是针对字处理文档.演示文稿和电子表格的国际化开放标准,可免费供多个应用程序在 ...

  7. Object.Destroy慎用

    Object.Destory Destory(Object)并没有立刻,马上,及时的删除这个Object. 举例 在使用NGUI的Table或Grid进行布局时,就需要注意了:尽量不要使用Destro ...

  8. Seajs是什么及sea.js 由来,特点以及优势

    Seajs是什么及sea.js 由来,特点以及优势 这篇文章主要介绍了Seajs的相关知识和和学习心得,适合刚接触SeaJS的同学,需要的朋友可以参考下,有更好的新手教程或文档,欢迎推荐.分享   1 ...

  9. FLEX的动画

    1.使用自带效果 在Flex里面不像在Flash里面随意制作动画了,Flex更趋向于应用程序,而不是动画制作了,所以没有了时间轴的概念.在Flex中使用动画效果,可以用Flex自带的Effect,或者 ...

  10. insertBefore的兼容性问题

    父级.insertBefore(新的元素,被插入的元素)方法 在指定的元素前面插入一个新元素 在ie下如果第二个参数的节点不存在,会报错 在其他浏览器下如果第二个参数不存在,则会以appendChil ...