当前位置: 首页 > news >正文

北大OJ 1001题

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

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

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

 

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

 

 

 

 

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

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

 

转载于:https://www.cnblogs.com/LonelyEnvoy/p/5948917.html

相关文章:

  • Android中软键盘弹出时底部菜单上移问题
  • to_date to_char
  • master-slave(主/从)模式
  • moogodb3.x总结
  • Maven中setting.xml 配置详解
  • 经历:easyui的layout自适应高度布局
  • Tern Sercer Tineout
  • 前端自动化之路之gulp,node.js
  • ajax技术的基本概述
  • python中单引号,双引号,多引号区别
  • Spring事务配置
  • 2016 ICPC大连站---F题 Detachment
  • POJ 3276 Face The Right Way 开关问题
  • hadoop3.0 alpha1 安装配置
  • 数据库-编程技巧
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • [译]前端离线指南(上)
  • axios请求、和返回数据拦截,统一请求报错提示_012
  •  D - 粉碎叛乱F - 其他起义
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • Java小白进阶笔记(3)-初级面向对象
  • JSDuck 与 AngularJS 融合技巧
  • JSONP原理
  • JS专题之继承
  • Mocha测试初探
  • nodejs:开发并发布一个nodejs包
  • Python进阶细节
  • Spring Cloud Feign的两种使用姿势
  • SQLServer插入数据
  • 飞驰在Mesos的涡轮引擎上
  • 给github项目添加CI badge
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 计算机常识 - 收藏集 - 掘金
  • 强力优化Rancher k8s中国区的使用体验
  • 用mpvue开发微信小程序
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • 函数计算新功能-----支持C#函数
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #Z0458. 树的中心2
  • (c语言)strcpy函数用法
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • .dwp和.webpart的区别
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .net图片验证码生成、点击刷新及验证输入是否正确
  • .vue文件怎么使用_我在项目中是这样配置Vue的
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具
  • [ 手记 ] 关于tomcat开机启动设置问题
  • [ 数据结构 - C++]红黑树RBTree