收藏 分享(赏)

程序设计实习第三讲数制转换和日期处理.ppt

上传人:Facebook 文档编号:3382677 上传时间:2018-10-21 格式:PPT 页数:54 大小:344KB
下载 相关 举报
程序设计实习第三讲数制转换和日期处理.ppt_第1页
第1页 / 共54页
程序设计实习第三讲数制转换和日期处理.ppt_第2页
第2页 / 共54页
程序设计实习第三讲数制转换和日期处理.ppt_第3页
第3页 / 共54页
程序设计实习第三讲数制转换和日期处理.ppt_第4页
第4页 / 共54页
程序设计实习第三讲数制转换和日期处理.ppt_第5页
第5页 / 共54页
点击查看更多>>
资源描述

1、程序设计实习 第三讲 数制转换和日期处理,主讲教师:田永鸿 2008年2月25日,2,通知,课程网页改在:http:/ 关于课程作业 作业提交的规定时间:为作业布置周的下下周末24:00前 POJ作业+平时邮件作业 POJ作业在http:/ 平时邮件作业:程设08_第X讲作业_姓名_学号(如程设08_第4讲作业_张三_100 ) POJ帐号规定 如果有计算概论课程的ID,可继续使用该ID,如果没有帐号,则使用学号注册自己的ID 昵称一律改为CPP08XX+ 自己喜欢的名称 (XX为小班号,详见分班情况),3,关于助教和分班,上机及助教分班已在网页上公布; 本班四个助教 01班:黄贝宁() 学号

2、:=748055 02班:唐大闰() 学号:748057748189 03班:潘晨光() 学号:748191748284 04班:栾俊义() 学号:748288748713,4,内容提要,关于 POJ 评测系统 程序阅读练习 程序设计练习 作业,5,关于 POJ 评测系统,对于每一个题目,评测系统收到源代码后,就用在提交框中指定的编译器进行编译和链接得到目标代码后,将其运行。 在运行过程中,如果程序要求从标准输入读入数据,则评测系统自动将已经存放在服务器端的测试数据提供给待测程序,待程序产生输出后,评测系统将程序产生的输出,与服务器端的标准答案做比较,如果相同,则程序被Accepted,否则出

3、错。,6,关于 POJ 评测系统,出错程序的错误产生序列如下: Compile Error,此时程序无法运行,可查看错误说明,如果程序有多个编译错,则只显示第一引起编译错的代码行引发的错误,如果你的程序在本机编译没错,通常有几种情况:选用了不正确的编译器,在VC+编程环境中编程由环境自动生成了“stdafx.h” 等等; Runtime Error,运行错,通常是数组、指针越界,或除零错;,7,关于 POJ 评测系统,Time Limit Exceeded,超时错,在每个问题的说明里都给出了时限,如果提交的程序在相应的时间内不结束,则评测系统自动将其终止,并返回超时错。引起超时错的原因主要有:

4、死循环(尤其是判断输入结束有误),算法或代码效率不够好; Output Limit Exceeded,输出过多,如果程序输出比标准答案多一倍以上的内容,则评测系统返回此错误。引发这一错误的原因多半是死循环。,8,关于 POJ 评测系统,Wrong Answer,结果错,这是最为复杂的一种错误,引发该错误的原因有很多,从读入数据不正确,到算法程序不正确,到输出不正确,都有可能引发该错误; Presentation Error,格式错,这是最为温和的一类错误,如果得到格式错,表明输入和程序的算法都没有错误,给出的答案是正确的,只是在输出时多余或少了空格空行等。有些时候不容易判格式错的问题也可能答案

5、正确格式不正确,但得到结果错。,9,关于 POJ 评测系统,Problem Disabled,题目有错,两种可能:该题已被删除,或者是在http:/ 上节课的例2(作业),1013 称硬币 问题描述 赛利有12枚银币。其中有11枚真币和1枚假币。假币看起来和真币没有区别,但是重量不同。 但赛利不知道假币比真币轻还是重。于是他向朋友借了一架天平。朋友希望赛利称三次就能找出假币并且确定假币是轻是重。例如:如果赛利用天平称两枚硬币,发现天平平衡,说明两枚都是真的。如果赛利用一枚真币与另一枚银币比较,发现它比真币轻或重,说明它是假币。经过精心安排每次的称量,赛利保证在称三次后确定假币。,12,1013

6、题,输入 输入有三行,每行表示一次称量的结果。赛利事先将银币标号为A-L。每次称量的结果用三个以空格隔开的字符串表示:天平左边放置的硬币 天平右边放置的硬币 平衡状态。其中平衡状态用up, down, 或 even表示, 分别为右端高、右端低和平衡。天平左右的硬币数总是相等的。 输出 输出哪一个标号的银币是假币; 并说明它比真币轻还是重。,13,1013题,输入样例 1 ABCD EFGH even ABCI EFJK up ABIJ EFGH even 输出样例 K is the counterfeit coin and it is light.,14,1013题,问题分析 此题并非要求你给

7、出如何称量的方案,而是数据已经保证三组称量后答案唯一。不是那道传统的智商测验题。 此题可以有多种解法,这里只介绍一种比较容易想到和理解的 逐一枚举法。,15,1013题,总体构想 逐一试探法 对于每一枚硬币x逐个试探:x比真币轻的猜测是否整理?若成立则输出; x比真币重的猜测是否整理?若成立则输出 isLight ? Yes. 输出, No. isHeavy ? Yes. 输出,16,1013题,定义变量存储称量结果 char left37,right37,result37;数组下标 3 代表3次称量; 数组下标 7 代表每次左右至多6枚硬币,多出一个字符位置是为了方便用字符串读取的函数。,1

8、7,1013题,逐一枚举硬币的代码for(char c = A; c = L; c+)if( isLight(c) )cout c “ is the counterfeit coin and it is light.n“;break;else if( isHeavy(c) )cout c “ is the counterfeit coin and it is heavy.n“;break;,18,1013题,bool isLight(char x) / 判断硬币x是否为轻的代码int i;for(i=0; i3; i+) / 判断是否与三次称量结果矛盾switch( resulti0 ) ca

9、se u: if( ! inRight(i,x) ) return false;break;case e: if(inRight(i,x) | inLeft(i,x) return false;break;case d: if(! inLeft(i,x) return false;break;return true; ,19,1013题,bool isHeavy(char x) /判断硬币x是否为重的代码int i;for(i=0; i3; i+) / 判断是否与三次称量结果矛盾switch( resulti0 ) case u: if( ! inLeft(i,x) ) return fals

10、e;break;case e: if(inRight(i,x) | inLeft(i,x) return false;break;case d: if(! inRight(i,x) return false;break;return true; ,20,1013题,bool inLeft(int i, char x) / 判断硬币x 是否在第i次称量左侧int j;for(j=0; jstrlen(lefti); j+) if(leftij = x ) return true;return false; bool inRight(int i, char x)/ 判断硬币x 是否在第i次称量右侧

11、int j;for(j=0; jstrlen(righti); j+) if(rightij= x) return true;return false; ,21,数值转换,22,数制转换(1),根据数制表示中相邻位的基数关系,数制可以分为两类 相邻位的基数为等比关系:如十进制 相邻位的基数为不等比关系:如时间表示 数制转换问题的一般处理方法 数值存储:不是十进制时,一般用字符型数组来存放,数组中每个元素分别存储它的一个数字。 十进制为中介:按位转换求和,得到十进制表示,再把十进制表示转换成所求的数制表示,结果也用字符型数组存储,23,数制转换(2),数制B的bmbm-1b1十进制的dndn-1

12、d1 数制B的中第i位的基数为basei (1=i=m) (basei * bi) 十进制的dndn-1d1 数制B的bmbm-1b1 数制B中相邻位的基数为等比关系:basei可表示为Ci (1)将dndn-1d1除以C,余数即为b1; (2)将dndn-1d1和C相除的结果再除以C,余数即为b2;直至计算出bm 。 数制B中相邻位的基数为不等比关系: (1)判断dndn-1d1在数制B中需要的位数m; (2)从高到低依次计算bm , bm-1 , , b1 。,#include #include double mysqrt(double guess, double x); bool goo

13、dEnough(double guess, double x); double improve(double guess, double x); void main()coutmysqrt(2.25,2.25) endl; double mysqrt(double guess, double x)if(goodEnough(guess,x) return guess;return mysqrt(improve(guess,x),x); bool goodEnough(double guess, double x) #define threshold 0.000001if(fabs(guess*

14、guess-x)threshold) return true;return false; double improve(double guess, double x)return (guess+x/guess)/2; 输出:,25,小结:如何阅读程序?,阅读程序不能象阅读小说 程序阅读的一些好方法 快速找到Main()和输入输出; 确定程序架构,画出流程图,确定调用关系; 找到关键语句段/函数,作为黑盒子单独阅读/调试。 阅读代码的格言 第一次分析一个程序时,main是一个好的起始点。 层叠if-else if-. -else 序列可以看作是由互斥选择项组成的选择结构。 有时,要想了解程序在某

15、一方面的功能,运行它可能比阅读源代码更为恰当。 在分析重要的程序时,最好首先识别出重要的组成部分。 了解局部的命名约定,利用它们来猜测变量和函数的功能用途。 推理地递归调用等同于一个回到函数开始处的循环。 ,26,程序阅读练习 例1,#include #include double mysqrt(double guess, double x); bool goodEnough(double guess, double x); double improve(double guess, double x); void main()coutmysqrt(2.25,2.25) endl; double

16、 mysqrt(double guess, double x)if(goodEnough(guess,x) return guess;return mysqrt(improve(guess,x),x); bool goodEnough(double guess, double x) #define threshold 0.000001if(fabs(guess*guess-x)threshold) return true;return false; double improve(double guess, double x)return (guess+x/guess)/2; 输出:1.5,27

17、,程序设计练习 例1,1331(确定进制)问题描述 6*9 = 42 对于十进制来说是错误的,但是对于13进制来说是正确的。即, 6(13) * 9(13) = 42(13), 而 42(13) = 4 * 131 + 2 * 130 = 54(10)。 你的任务是写一段程序读入三个整数p, q和 r,然后确定一个进制 B (2=B=16) 使得 p * q = r. 如果 B有很多选择, 输出最小的一个。 例如: p = 11, q = 11, r = 121. 则有 对于禁止3:11(3) * 11(3) = 121(3) 因为 11(3) = 1 * 31 + 1 * 30 = 4(10

18、) 和 121(3) = 1 * 32 + 2 * 31 + 1 * 30 = 16(10)。 对于进制 10,有 11(10) * 11(10) = 121(10)。 这种情况下,应该输出 3。如果没有合适的进制,则输出 0。,28,程序设计练习 例1,输入 输入有 T组测试样例。 T在第一行给出。每一组测试样例占一行,包含三个整数p, q, r。 p, q, r 的所有位都是数字,并且1=p,q, r=1,000,000。 输出 对于每个测试样例输出一行。该行包含一个整数 - 即使得p * q = r成立的最小的B。如果没有合适的B,则输出 0。,29,程序设计练习 例1,输入样例 3 6

19、 9 42 11 11 121 2 2 2 输出样例 13 3 0,30,程序设计练习 例1,此题没难度,逐一试探法,注意一些实现的细节。 选择一个进制B(2=B=16),按照该进制将被乘数、乘数、乘积分别转换为10进制,然后判断等式是否成立。选择使得等式成立的最小的B。 分别用一个字符型数组存储p、q、r的各位数字符号。先以字符串的方式读入p、q、r,然后按照不同的进制将它们转换成十进制数,判断是否相等。,31,程序设计练习 例1,long b2ten(char *x, int b) int ret = 0; int len = strlen(x); for(int i = 0; i = b

20、) return -1; ret *= b; ret += xi - 0 ; return (long)ret; ,32,程序设计练习 例1,#include #include long b2ten(char* x,int b); void main( ) int n;char p8,q8,r8; scanf(“%d“, ,33,小结:程序设计的一般步骤,问题分析 理解问题,确定任务、输入、输出 找到关键条件(如数据的边界、关键数据的性质等) 确定解题的思路 框架设计 用文字描述主程序的框架 包括输入输出、主要程序块 确定主要数据的存储结构 将公用的处理封装成函数 代码设计 将程序框架变成代码

21、 编辑调试,34,程序设计练习 课堂练习1,1565(skew数) 问题描述 在 skew binary表示中, 第 k 位的值xk表示xk* (2k+1-1)。 每个位上的可能数字是0 或 1,最后面一个非零位可以是2, 例如, 10120(skew) = 1 * (25-1) + 0 * (24-1) + 1 * (23-1) + 2 * (22-1) + 0 * (21-1) = 31 + 0 + 7 + 6 + 0 = 44 前十个skew数是 0, 1, 2, 10, 11, 12, 20, 100, 101, and 102。,35,程序设计练习 课堂练习1,输入 输入包含一或多行

22、,每行包含一个整数n。 如果 n = 0 表示输入结束,否则n是一个skew 数. 输出 对于每一个输入,输出它的十进制表示。转换成十进制后, n 不超过 231-1 = 2147483647.,36,程序设计练习 课堂练习1,输入样例 10120 200000000000000000000000000000 10 1000000000000000000000000000000 11 100 11111000001110000101101102000 0,输出样例 44 2147483646 3 2147483647 4 7 1041110737,37,解题思路,skew数中相邻位的基数为不等

23、比关系,因此先需计算基数 对于长度为k的skew数,最后一位数字的基数为2k-1 用一个整型数组base31,依次从低到高存放skew数的基数,38,日期和时间处理,39,日期和时间处理,不同日历表示法之间的相互转换 基本思路:找到一种公共的基准,并通过基准进行不同日历之间的转换。 易出问题处:细节处理(如出错),40,程序设计练习 例2,POJ 2080 问题描述: 在我们现在使用的日历中, 闰年被定义为能被4整除的年份 但是能被100整除而不能被400整除的年是例外,它们不是闰年。例如:1700, 1800, 1900 和 2100 不是闰年,而 1600, 2000 和 2400是闰年。

24、 给定从公元2000年1月1日(周六)开始逝去的天数,你的任务是给出这一天是哪年哪月哪日星期几。,41,程序设计练习 例2,输入: 输入包含若干行,每行包含一个正整数,表示从2000年1月1日开始逝去的天数。输入最后一行是1, 不必处理。可以假设结果的年份不会超过9999。 输出: 对每个测试样例,输出一行,该行包含对应的日期和星期几。 格式为“YYYY-MM-DD DayOfWeek”, 其中 “DayOfWeek” 必须是下面中的一个: “Sunday“, “Monday“, “Tuesday“, “Wednesday“, “Thursday“, “Friday“ and “Saturda

25、y“。,42,程序设计练习 例2,样例输入 1730 1740 1750 1751 -1 样例输出 2004-09-26 Sunday 2004-10-06 Wednesday 2004-10-16 Saturday 2004-10-17 Sunday,43,程序设计练习 例2,问题解答 此题为典型的日期处理程序,没有难度,只是编程需要特别细心,日期处理的程序非常容易出错。 基本思路: 确定星期几; 确定年;闰年366天,否则365天 确定月;每个月长短不同 确定日。,44,程序设计练习 例2,#include void main() int m112=31,28,31,30,31,30,31

26、,31,30,31,30,31;int m212=31,29,31,30,31,30,31,31,30,31,30,31;char week710=“Saturday“,“Sunday“,“Monday“,“Tuesday“,“Wednesday“,“Thursday“,“Friday“;int days, weekday; scanf(“%d“, ,45,程序设计练习 例2,ithyear -; days += daysinyear; int ithmonth=0; while(days 0) /确定月if(daysinyear = 365) days -= m1ithmonth;else

27、days -= m2ithmonth; ithmonth +; if(daysinyear = 365) days += m1ithmonth-1; /确定天else days += m2ithmonth-1; printf(“%d-%02d-%02d %sn“,2000+ithyear,ithmonth,days,weekweekday);scanf(“%d“, / while / main,46,程序设计练习 例3,问题描述: 一种细菌的繁殖速度是每天成倍增长。例如:第一天有10个,第二天就变成20个,第三天变成40个,第四天变成80个,。 现在给出第一天的日期和细菌数目,要你写程序求出到

28、某一天的时候,细菌的数目。,47,程序设计练习 例3,输入 第一行有一个整数n,表示测试数据的数目。其后n行每行有5个整数,整数之间用一个空格隔开。第一个数表示第一天的月份,第二个数表示第一天的日期,第三个数表示第一天细菌的数目,第四个数表示要求的那一天的月份,第五个数表示要求的那一天的日期。 已知第一天和要求的一天在同一年并且该年不是闰年,要求的一天一定在第一天之后。数据保证要求的一天的细菌数目在长整数(long)范围内。 输出 对于每一组测试数据,输出一行,该行包含一个整数,为要求的一天的细菌数。,48,程序设计练习 例3,样例输入 2 1 1 1 1 2 2 28 10 3 2 样例输出

29、 2 40,49,解题思路,求给定的两天之间间隔的天数m,第一天的细菌数乘以2的m次方就是题目的答案 难点:每月的天数不很规则,程序处理过程中较为复杂 用一个数组将每个月的天数存起来 算法框架 读入测试样例数n; 做n次 (1)读入两个日期及第一天的细菌数; (2)将两个日期转换为当前的第几天; (3)得到两个天数的差,即他们中间间隔的天数m; (4)用第一天的细菌数乘以2的m次方得到x; (5)输出x,#include void main() int nDays12=31,28,31,30,31,30,31,31,30,31,30,31;int n;scanf(“%d“, ,51,程序设计练

30、习 课堂练习2,2210 问题描述 有一种特殊的日历法,它的一天和我们现在用的日历法的一天是一样长的。它每天有10个小时,每个小时有100分钟,每分钟有100秒。10天算一周,10周算一个月,10个月算一年。 现在要你编写一个程序,将我们常用的日历法的日期转换成这种特殊的日历表示法。这种日历法的时、分、秒是从0开始计数的。日、月从1开始计数,年从0开始计数。秒数为整数。假设 0:0:0 1.1.2000 等同于特殊日历法的 0:0:0 1.1.0。,52,程序设计练习 课堂练习2,输入 第一行是一个整数 N ,表示测试样例的数目。 每个测试样例包含一行,格式为: “hour:minute:se

31、cond day.month.year” 日期总是合法的,并且 2000 = year = 50000. 输出 对于每个测试样例输出一行,该行包含转换后得到的特殊日历表示法,形如:“mhour:mmin:msec mday.mmonth.myear“,53,程序设计练习 课堂练习2,输入样例 7 0:0:0 1.1.2000 10:10:10 1.3.2001 0:12:13 1.3.2400 23:59:59 31.12.2001 0:0:1 20.7.7478 0:20:20 21.7.7478 15:54:44 2.10.20749,输出样例 0:0:0 1.1.0 4:23:72 26.5.0 0:8:48 58.2.146 9:99:98 31.8.0 0:0:1 100.10.2000 0:14:12 1.1.2001 6:63:0 7.3.6848,54,20080225作业,2965 2351 2967 1565 1008(选做) 2210(选做),

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 中等教育 > 小学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报