免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: DNFCF
打印 上一主题 下一主题

[算法] 变态的算法题 [复制链接]

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
11 [报告]
发表于 2011-04-28 22:03 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
12 [报告]
发表于 2011-04-28 22:04 |只看该作者
回复 8# cjaizss


    不懂。。。。

论坛徽章:
0
13 [报告]
发表于 2011-04-28 22:05 |只看该作者
回复  DNFCF


      硬件环境是什么
pmerofc 发表于 2011-04-28 22:03



    硬件可以不考虑,这个主要是考算法。。。。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
14 [报告]
发表于 2011-04-28 22:07 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
15 [报告]
发表于 2011-04-28 22:09 |只看该作者
回复  DNFCF


    问题是要求3分钟,有的机器快,有的机器慢
pmerofc 发表于 2011-04-28 22:07



    老大,你先忽略这个时间限制行不??先给个算法思路吧。。。。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
16 [报告]
发表于 2011-04-28 22:13 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
17 [报告]
发表于 2011-04-28 22:28 |只看该作者
我的想法和10楼差不多

先把 0~9 的21次方算好存起来
然后从 10的20次方开始 到 10的21次方-1 穷举 计算 ...
pmerofc 发表于 2011-04-28 22:13



    问题是数太大了,会溢出的啊???

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
18 [报告]
发表于 2011-04-28 22:37 |只看该作者
问题是数太大了,会溢出的啊???
DNFCF 发表于 2011-04-28 22:28


不是穷举,是凑数。
看看每个数的差距
linux-0gt0:~ # bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
for(i=1;i<=9;i++)
print i^21,"\n"
1
2097152
10460353203
4398046511104
476837158203125
21936950640377856
558545864083284007
9223372036854775808
109418989131512359209

论坛徽章:
0
19 [报告]
发表于 2011-04-28 22:57 |只看该作者
不是穷举,是凑数。
看看每个数的差距
linux-0gt0:~ # bc
bc 1.06
Copyright 1991-1994, 1997, 199 ...
cjaizss 发表于 2011-04-28 22:37



    可是在C语言下,好像超过10位就会溢出啊,怎么解决啊??

论坛徽章:
0
20 [报告]
发表于 2011-04-29 06:30 |只看该作者
本帖最后由 KBTiller 于 2011-04-29 06:40 编辑
可是在C语言下,好像超过10位就会溢出啊,怎么解决啊??
DNFCF 发表于 2011-04-28 22:57



    想办法创造新的“类型”。编程的乐趣之一就是这种创造性。感觉你还没体会到什么是数据结构
    手懒,抄段书(自《狂人C》第3章)给你,希望能对你有所启发


1976年,著名的计算机大师、Pascal语言之父Niklaus Wirth提出

       算法 + 数据结构 = 程序



Algorithms + Data Structures = Programs
    ……
   例题:编程求123456×654321
   ……
   

难道C语言对待如此简单的小学生都会做的算术问题都束手无策吗?倒也不是这样,办法是有的,但需要你自己去想。编程的乐趣大抵在此。

由于本题目问题的核心在于两个较大的数相乘超过了int类型的范围,所以可以考虑把乘数拆成较小的数。比如

123456×654321=123×103+456)×(654×103+321

=123×103×(654×103+321+ 456×(654×103+321

=123×103×654×103+123×103×321+ 456×654×103+ 456×321

=123×654×106+123×321×103+ 456×654×103+ 456×321

=123×654)×106+123×321+ 456×654)×103+ 456×321

如果能分别求出(123×654)、(123×321+ 456×654)、456×321,问题不就解决了吗?而(123×654)、(123×321+ 456×654)、456×321,可以确信,是可以用int类型表示的。

在这种情况下,用一个int变量存储123456654321是不行的,需要两个,一个用来记录123456654321的前三位,另一个记录后三位。这种对数据的组织和安排方式,就是所谓的数据结构。尽管这里的还只是一种很粗糙的数据结构。此外还可以发现,设计数据结构首先涉及到的问题恰恰是选择合适的数据类型。

在这种数据结构下的算法就是:首先求出(123×654)、(123×321+ 456×654)、456×321。可以断定积的最后三位是456×3211000求余的结果,最前面几位是(123×654+123×321+ 456×654/103,中间三位的值为(123×321+ 456×654%103+456×321/1000。(这些示意性的东西叫伪代码(Pseudocode

从对算法的描述中还可以发现,积最好用三个int来表示。

所以,所谓的算法无非就是对操作步骤的描述。描述算法的方式有很多,其中之一就是使用自然语言来描述。用C语言描述的算法和数据结构就是C代码。

  1. /*编程求123456*654321*/

  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. #define CS1 123456  //乘数1
  5. #define CS2 654321  //乘数2
  6. #define YQ  1000    //一千

  7. int main(void)
  8. {
  9. int cs1_q3w,cs1_h3w,cs2_q3w,cs2_h3w;//乘数1、乘数2的前3位和后3位
  10. int ji_q,ji_z,ji_h; //积的前、中、后三个部分
  11.   
  12. cs1_q3w = CS1 / YQ ;
  13. cs1_h3w = CS1 % YQ ;
  14.   
  15. cs2_q3w = CS2 / YQ ;
  16. cs2_h3w = CS2 % YQ ;

  17. //求出(123×654)、(123×321+ 456×654)、456×321
  18. ji_q = cs1_q3w * cs2_q3w ;
  19. ji_z = cs1_q3w * cs2_h3w + cs1_h3w * cs2_q3w ;
  20. ji_h = cs1_h3w * cs2_h3w ;  

  21. //进位处理,注意:次序很重要
  22. ji_q = ji_q + ji_z / YQ ;
  23. ji_z = ji_z % YQ + ji_h / YQ ;
  24. ji_h = ji_h % YQ ;
  25. //输出  
  26. printf("%d×%d == %d%d%d\n" , CS1 , CS2 , ji_q , ji_z ,ji_h );

  27. system("PAUSE");
  28. return 0;
  29. }
复制代码

程序输出

123456×654321 == 80779853376

程序代码3-5的输出相比,这个结果至少可以说可信度很高,尽管我们还无法确信。

增强对程序正确性信心的方法只有通过测试。由于这段代码对于两个不多于6位的十进制数都应该成立,所以可以选择易于验算的情况运行程序,比如把123456改为100000再运行程序

然而,很遗憾,程序求100000×654321的结果竟然是

100000×654321 == 654321000

造成这个错误的原因是,代码中ji_zji_h表示的都是三位的十进制数,但当它们的值为0时,%d这种格式只输出10而不是30。改进的办法是把它们对应的%d改成%03d。其中3表示输出三位,0表示如果前面有空格则填充0(可以自己上机对比一下%03d%3d和%d之间的区别)。

把输出改写为

printf("%d×%d == %d%03d%03d\n" , CS1 , CS2 , ji_q , ji_z ,ji_h );
之后,可以发现程序求100000×654321的结果是正确的。如果还不放心,可以再找一些数据进行测试。


您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP