北大OJ 1001题
题目:输入一序列的正实数和幂次(正整数)对,然后打印结果(具体的比这个精细)
这道题是关于大数计算的(大数求幂),从开始建立思路,到写代码、调式到最后被AC以及最终的优化,总共用了差不多一天的时间。开始AC时使用空间500K,时间37MS,最后一次AC空间400K,时间0MS,有很大提高。这主要归功于加大了每次的数据处理量,减少了重计算次数以及降低循环代码量。还有就是在使用了二分递归,避免了重复计算。不好的一点是代码量太大,并且使用了太多的变量。
不管怎么样,为这道题付出了很多想法,后来的一些大的优化主要来自对底层的深入理解,代码的整体实现粒度是很细的,阅读起来可能会有些困难,但很是值得推敲的,具体实现代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- void add(char *s1, char *s2);
- char *multi(char *s1, char *s2);
- char *result(char *s, int n);
- int main(void) {
- char ch[100];
- char *res;
- int num, np;
- char tem, *temp1, *temp2;
- char *chp;
- while ( scanf("%s%d", ch, &num) != EOF ) {
- chp = ch + strspn(ch, "0"); // 去掉前导0
- temp1 = &ch[strlen(ch)-1];
- if ( (temp2 = strchr(ch, '.')) != NULL ) { // 如果有小数点
- while ( *temp1 == '0' ) // 去掉小数末尾的0
- *temp1-- = 0;
- np = strlen(temp2) - 1;
- np *= num; // 小数位的num倍是最终结果的小数位数
- memmove(temp2, temp2+1, strlen(temp2)); // 去掉小数点
- }
- else
- np = 0; // 整数
- res = result(chp, num);
- // printf("res: %s\n", res);
- temp1 = res + strspn(res, "0");
- temp2 = &res[strlen(res) - np]; // 定位小数点
- if ( temp1 >= temp2 && np != 0 ) // 如果结果小于1
- printf("%c%s\n", '.', temp2);
- else if ( np == 0 ) // 如果是整数
- printf("%s\n", temp1 == temp2 ? 0 : temp1);
- else {
- tem = *temp2; // 将该放小数点位置的源字符保存
- *temp2++ = 0; // 这里将源结果字符串断开,块式输出效率高
- printf("%s%c%c%s\n", temp1,
- '.', tem,
- *temp2 == 0 ? "" : temp2);
- }
- free(res);
- }
- return 0;
- }
- char *result(char *s, int n) {
- char *res, *ch1, *ch2;
- if ( n == 1 )
- return multi(s, "1"); // 返回统一类型的可被free掉的数据空间
- else if ( n == 2 )
- return multi(s, s);
- else if ( n > 2 ) {
- ch1 = result(s, n >> 1); // 二分递归计算
- if ( n % 2 != 0 ) {
- ch2 = result(s, n - (n >> 1));
- res = multi(ch1, ch2);
- free(ch2); // result函数返回值得释放掉
- }
- else // 如果n是偶数,可避免重复计算
- res = multi(ch1, ch1);
- free(ch1);
- return res;
- }
- }
- char *multi(char *s1, char *s2) {
- int i1, i2;
- char *ch1, *ch2, *cp1, *cp2, *cp3;
- char chp[18];
- int i, j, num, dis;
- long long j1, j2, j3; // 加大每次计算量
- i1 = strlen(s1);
- i2 = strlen(s2);
- ch1 = (char *)malloc(i1 + i2 + 2); // 1 bit '\0', 1 carry bit(reserved for)
- if ( strncmp(s2, "1", 1) == 0 && i2 == 1 ) {
- memcpy(ch1, s1, i1+1);
- return ch1;
- }
- ch2 = (char *)malloc(i1 + i2 + 1); // 1 bit '\0'
- memset(ch1, '0', i1 + i2 + 2);
- ch1[i1+i2+1] = 0;
- i = i2;
- while ( i > 0 ) {
- if ( i >= 8 ) // 和j,每次各可处理8位
- dis = 8;
- else
- dis = i;
- i -= dis;
- memset(ch2, '0', i1 + i2 + 1); // ch2每次循环都可能被修改
- ch2[i1+i2] = 0;
- cp1 = &s1[i1];
- cp2 = &s2[i2];
- cp3 = &ch2[i1 + i]; // i1+i2-(i2-i)=i1+i, 每次循环往左移动dis位,表示和记录进位
- memcpy(chp, cp2 - i2 + i, dis);
- chp[dis] = 0;
- j2 = atoi(chp);
- j = i1;
- while ( j > 0 ) {
- if ( j >= 8 ) // 最多8位迭代处理与j2相乘
- num = 8;
- else
- num = j;
- cp1 -= num;
- memcpy(chp, cp1, num);
- chp[num] = 0;
- j1 = atoi(chp);
- memcpy(chp, cp3, dis); // cp3记录进位,最多有dis位
- chp[dis] = 0;
- j3 = atoi(chp);
- snprintf(chp, 18, "%lld", j1 * j2 + j3);
- j1 = strlen(chp);
- memcpy(cp3 -j1 + dis, chp, j1); // 数据向右对齐
- cp3 -= num; // 定位到下次计算进位可能占据空间的开头地址
- j -= num;
- }
- add(ch1, ch2); // 将新的计算结果与前面的相加,最后可获得最后结果
- }
- free(ch2);
- return ch1;
- }
- void add(char *s1, char *s2) {
- char *cp1, *cp2, *cp3, *ch;
- char chp[18];
- int num, n1, n2;
- long long i, j, k;
- s2 += strspn(s2, "0");
- n1 = strlen(s1); // make sure n1 > n2
- if ( (n2 = strlen(s2)) == 0 )
- return;
- ch = (char *)malloc(n1+1);
- memset(ch, '0', n1);
- ch[n1] = 0;
- cp1 = &s1[n1];
- cp2 = &s2[n2];
- cp3 = &ch[n1 - 1];
- while ( n2 > 0 ) { // must validate enough memory
- if ( n2 >= 16 )
- num = 16;
- else
- num = n2;
- cp1 -= num;
- cp2 -= num;
- memcpy(chp, cp1, num);
- chp[num] = 0;
- i = atoll(chp);
- memcpy(chp, cp2, num);
- chp[num] = 0;
- j = atoll(chp);
- memcpy(chp, cp3, 1);
- chp[1] = 0;
- k = atoll(chp);
- snprintf(chp, 18, "%lld", i + j + k);
- i = strlen(chp);
- cp3 -= i - 1;
- memcpy(cp3, chp, i);
- cp3 += i - 1 - num;
- n2 -= num;
- }
- memcpy(s1, ch, n1);
- free(ch);
- }
原文转自 http://blog.csdn.net/chiichen/article/details/6685858
原作者为 chiichen. 请尊重原作者版权
北大OJ 1001题的更多相关文章
- acm入门 杭电1001题 有关溢出的考虑
最近在尝试做acm试题,刚刚是1001题就把我困住了,这是题目: Problem Description In this problem, your task is to calculate SUM( ...
- 【Java】深深跪了,OJ题目Java与C运行效率对比(附带清华北大OJ内存计算的对比)
看了园友的评论之后,我也好奇清橙OJ是怎么计算内存占用的.重新测试的情况附在原文后边. -------------------------------------- 这是切割线 ----------- ...
- hdu 5288||2015多校联合第一场1001题
pid=5288">http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a ar ...
- Sublime Text3 配置C++(附oj刷题常用模板)
# 下载对应平台的sublime sublime最新版下载, 字体样式个人喜欢Consolas, 另附注册码: -– BEGIN LICENSE -– TwitterInc 200 User Lice ...
- 九度oj 1001 A+B for Matrices 2011年浙江大学计算机及软件工程研究生机试真题
题目1001:A+B for Matrices 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:15235 解决:6172 题目描述: This time, you are supposed ...
- Leetcode OJ 刷题
Valid Palindrome吐槽一下Leetcode上各种不定义标准的输入输出(只是面试时起码能够问一下输入输出格式...),此篇文章不是详细的题解,是自己刷LeetCode的一个笔记吧,尽管没有 ...
- 九度OJ做题记录 更新.....
2015年1月7日 20:34:23 题目1007:奥运排序问题 有点意思,以后想另外方法快速做出来 2015年1月7日 21:03:56 有一个技巧就是,写了三个比较函数cmp1,cmp2,cmp ...
- 牛客OJ——[编程题]A+B和C__如何输入多组测试数据(测试OK)
几个要注意的地方: (1)Java OJ,必须将类名写成Main (2)关于如何输入多组测试数据,用二维数组去存储是一个方法,直接在while里面做也可以 但是如果 (3)关于整形 ...
- HDU 4738 Caocao's Bridges (2013杭州网络赛1001题,连通图,求桥)
Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
随机推荐
- 使用virt-manager创建和管理虚拟机
1.虚拟机管理程序和虚拟机管理 一个服务器上只安装单一操作系统的时代已经过去,单个服务器可通过安装多个虚拟机来运行不同操作系统.虚拟机的大量使用减少了所需的服务其硬件,降低了服务器的功耗,但却带来了另 ...
- Microsoft.Bcl.Build 1.0.10 稳定版发布
Microsoft.Bcl.Build 1.0.10 稳定版发布 解决了之前 1.0.8 在未下载相应的Nuget Package 的情况下项目无法加载的情况 但由于 Microsoft.Net.Ht ...
- AI (Adobe Illustrator)详细用法(二)
本文主要是介绍形状的创建与编辑. 一.系列形状工具 1.矩形工具 矩形的作用很大,比如输入框,按钮,图片的大小,比如相片应用中每一个照片占的比例是多大. 初步的UI图的话,会画矩形和圆角矩形就够了. ...
- NopCommerce功能与特点介绍
[本文转自]http://www.cnblogs.com/nopcommerce-b2c/p/3758676.html 前两节我们主要介绍了NopCommerce下载与安装和NopCommerce中文 ...
- Mobizen免帐号版
Mobizen电脑控制手机软件,是远程软件专家RSUPPORT公司研发的一款全新产品,可以通过电脑(web页面和客户端两种形式)远程控制安卓系统的智能手机和平板电脑,三种连接方式3G/4G.Wifi. ...
- 网络之OSI七层模型
1. 物理层:设备之间的比特流的传输,物理接口,电气特性等 2. 数据链路层:成帧,用MAC地址访问媒介,错误检测与修正 3. 网络层:提供逻辑地址(IP),选路 4. 传输层:可靠与不可靠的 ...
- 实例变量和静态变量(或类变量static)
一个类通过使用运算符new可以创建多个不同的对象,这些对象将被分配不同的内存空间,准确的说法是:不同对象的实例变量将被分配不同的内存空间,如果类中有类变量,那么所有对象的这个类变量都被分配到同一处内存 ...
- 怎样使用VMware Workstation(虚拟机)
怎样使用VMware Workstation(虚拟机) 听语音 浏览:66981 | 更新:2010-12-06 16:26 | 标签:vmware 1 2 3 4 5 6 7 分步阅读 一键约师傅 ...
- [转]关于vs调试正确。但是发布到iis就出现无法访问后天局面
最近使用extjs+ashx进行ajax请求过程操作的时候发现一个问题..当我把程序发布到iis的时候就出现一只不执行到success回调函数. 当弹出状态值一看尽然是500.我就纳闷了.又没有语法错 ...
- [No00005A]word多文档合一
2个方法:法一,一个个插入,法二,一次性插入多个. 法一: 视图->大纲视图 点击 大纲 -> 显示文档 点击插入,逐个插入文档.. 最终 将视图调回页面视图..结束. 法二: 插入 - ...