1、2018/9/4,1,ACM程序设计,输入输出格式,2018/9/4,2,ACM题目特点,由于ACM竞赛题目的输入数据和输出数据一般有多组(不定),并且格式多种多样,所以,如何处理题目的输入输出是对大家的一项最基本的要求。这也是困扰初学者的一大问题。下面,分类介绍:,2018/9/4,3,一个超级简单的题目(ex-1):,Problem Description Your task is to calculate a + b. Input The input will consist of a series of pairs of integers a and b, separated by a
2、 space, one pair of integers per line. Output For each pair of input integers a and b you should output the sum of a and b in one line, and with one line of output for each line in input.Sample input 1 5 10 20 Sample output 6 30,2018/9/4,4,初学者很常见的一种写法:,#include void main() int a,b;scanf(“%d %d”, ,20
3、18/9/4,5,有什么问题呢?,这就是下面需要解决的问题,基本输入输出,2018/9/4,6,输入第一类:,输入不说明有多少个Input Block,以EOF为结束标志。 参见:ex-1.,2018/9/4,7,ex-1源代码:,#include int main() int a,b;while(scanf(“%d %d“,2018/9/4,8,本类输入解决方案:,C语法:while(scanf(“%d %d“,&a, &b) != EOF) C+语法:while( cin a b ) ,2018/9/4,9,说明:,Scanf函数返回值就是读出的变量个数,如:scanf( “%d %d”,
4、 如果a和b都被成功读入整数,那么scanf的返回值就是2; 如果只有a被成功读入整数,返回值为1; 如果a和b都未被成功读入整数,返回值为0; 如果遇到错误或遇到end of file,返回值为EOF EOF是一个预定义的常量,等于-1。,2018/9/4,10,输入第二类:,输入一开始就会说有N个Input Block,下面接着是N个Input Block。 ex-2 Problem Description Your task is to calculate a + b. Input Input contains an integer N in the first line, and th
5、en N lines follow. Each line consists of a pair of integers a and b, separated by a space, one pair of integers per line. Output For each pair of input integers a and b you should output the sum of a and b in one line, and with one line of output for each line in input. Sample input 2 1 5 10 20 Samp
6、le output 6 30,2018/9/4,11,ex-2源代码:,#include int main() int n,i,a,b;scanf(“%d“,2018/9/4,12,本类输入解决方案:,C语法:scanf(“%d“, i+ ) ,2018/9/4,13,输入第三类:,输入不说明有多少个Input Block,但以某个特殊输入为结束标志。 ex-3 Problem Description Your task is to calculate a + b. Input Input contains multiple test cases. Each test case contain
7、s a pair of integers a and b, one pair of integers per line. A test case containing 0 0 terminates the input and this test case is not to be processed. Output For each pair of input integers a and b you should output the sum of a and b in one line, and with one line of output for each line in input.
8、 Sample input 1 5 10 20 0 0 Sample output 6 30,2018/9/4,14,ex-3源代码:,#include int main() int a,b;while(scanf(“%d %d“,上面的程序有什么问题?,杜绝低级错误!,2018/9/4,15,本类输入解决方案:,如果最后一行是以一个0结尾则: C语法:while(scanf(“%d“,&n) & n!=0 ) C+语法:while( cin n & n != 0 ) ,2018/9/4,16,输入第四类:,输入是一整行的字符串的 参见:POJ_1298 http:/ Sample Input
9、 START NS BFW, JAJSYX TK NRUTWYFSHJ FWJ YMJ WJXZQY TK YWNANFQ HFZXJX END START N BTZQI WFYMJW GJ KNWXY NS F QNYYQJ NGJWNFS ANQQFLJ YMFS XJHTSI NS WTRJ END START IFSLJW PSTBX KZQQ BJQQ YMFY HFJXFW NX RTWJ IFSLJWTZX YMFS MJ END ENDOFINPUT,2018/9/4,17,本类输入解决方案:,C语法:char buf20; gets(buf); C+语法:如果用string
10、 buf;来保存:getline( cin , buf ); 如果用char buf 255 ; 来保存: cin.getline( buf, 255 );,2018/9/4,18,说明:,scanf(“ %s%s”,str1,str2),在多个字符串之间用一个或多个空格分隔; 若使用gets函数,应为gets(str1); gets(str2); 字符串之间用回车符作分隔。 通常情况下,接受短字符用scanf函数,接受长字符用gets函数。 而getchar函数每次只接受一个字符,经常c=getchar()这样来使用。,2018/9/4,19,说明:cin.getline的用法,getlin
11、e 是一个函数,它可以接受用户的输入的字符,直到已达指定个数,或者用户输入了特定的字符。它的函数声明形式(函数原型)如下:istream 不用管它的返回类型,来关心它的三个参数: char line: 就是一个字符数组,用户输入的内容将存入在该数组内。 int size : 最多接受几个字符?用户超过size的输入都将不被接受。 char endchar :当用户输入endchar指定的字符时,自动结束。默认是回车符。,2018/9/4,20,说明续,结合后两个参数,getline可以方便地实现: 用户最多输入指定个数的字符,如果超过,则仅指定个数的前面字符有效,如果没有超过,则用户可以通过回
12、车来结束输入。 char name4; cin.getline(name,4,n); 由于 endchar 默认已经是 n,所以后面那行也可以写成: cin.getline(name,4);,2018/9/4,21,练习:,以下题目属于哪一类输入?POJ_1423 http:/ POJ_1519 http:/ 更多类型 http:/ http:/ http:/ Block对应一个Output Block,Output Block之间空行。 ex-4 Problem Description Your task is to calculate the sum of some integers. I
13、nput Input contains an integer N in the first line, and then N lines follow. Each line starts with a integer M, and then M integers follow in the same line. Output For each group of input integers you should output their sum in one line, and you must note that there is a blank line between outputs.
14、Sample input 3 4 1 2 3 4 5 1 2 3 4 5 3 1 2 3 Sample output 10 15 6,2018/9/4,23,以下方法什么问题?,C语法: printf(“%dnn“,ans); C+语法: . cout ans endl endl; ,2018/9/4,24,Ex-4正确源代码,#include int main() int icase,n,i,j,a,sum;scanf(“%d“,2018/9/4,25,解决办法:,C语法:for (k=0;kcount;k+) while () printf(“ %dn“,result); if (k!=c
15、ount-1) printf(“n“); C+语法:类似,输出语句换一下即可。,2018/9/4,26,思考:,思考以下题目的输入格式http:/ http:/ 不要在for语句中定义类型 _int64不支持,可以用long long代替 使用了汉语的标点符号 itoa不是ANSI函数能将整数转换为字符串而且与ANSI标准兼容的方法是使用sprintf()函数int num = 100; char str25; sprintf(str, “ %d“ , num); 另外,拷贝程序容易产生错误,2018/9/4,29,不常规的编程方式,Printf和cout混用的问题 以下的程序输出什么? #i
16、nclude #include int main() int j=0;for(j=0;j5;j+)cout“j=“;printf(“%dn“,j);return 0; ,2018/9/4,30,什么问题?,一个带缓冲输出(cout) 一个不带缓冲输出(printf) Goole你的问题,充分利用网络资源,2018/9/4,31,相互学习进步,总结一些非算法方面的错误; 将心得相互交流; 避免初级错误是准备竞赛的第一步; 不要轻视初级错误。,2018/9/4,32,菜鸟之伤 ACM菜鸟的21个经典错误,2018/9/4,33,以HDU1089 AB为例,Sample Input 1 5 10 2
17、0 Sample Output 6 30,2018/9/4,34,菜鸟之伤(1),#include void main() int a,b; scanf(“%d%d”, ,2018/9/4,35,菜鸟之伤(1),总结:程序不能处理多组数据的问题是最常见的入门问题,只要掌握几种常见的类型,就可以轻松掌握了,具体处理方法曾在第一次课件有详细描述,这里省略了,2018/9/4,36,菜鸟之伤(2),#include void main() int a,b; while(scanf(“%d%d”, ,2018/9/4,37,菜鸟之伤(2),总结:文件结束符EOF的值是-1而不是0,所以while(sc
18、anf()!=0)常常会因为死循环而造成TLE,这个必须牢记。说明:不仅仅菜鸟,很多老鸟也常常因为不注意这点而犯错误,而且还常常因为想不到会犯这种低级错误而想不到原因。,2018/9/4,38,菜鸟之伤(3),#include void main() int a,b; while(scanf(“%d%d”, ,2018/9/4,39,菜鸟之伤(3),总结:while 或者 for循环的条件外面误加了分号,编译不影响,但是结果循环体没有真正得到多次执行; 说明:菜鸟常犯的错误,往往因为编译能通过而不能迅速察觉,尤其比赛中 提醒:当你将scanf();语句加上while循环以处理多组数据问题的时候
19、尤其注意因为之前有分号,很容易忘记去掉!,2018/9/4,40,菜鸟之伤(4),#include void main() int a,b; while(scanf(“%d%d”, ,2018/9/4,41,菜鸟之伤(4),总结:C语言中,赋值符号和判断是否相等的逻辑符号具有完全不同的含义,往往因为我们的习惯问题,在编程中误将判断是否相等的逻辑符号写成赋值符号。同样的,这种失误也会因为不影响编译而影响查错的时间。说明:菜鸟常犯的错误,但是有过几次教训就会牢记了,呵呵,2018/9/4,42,以HDU1001 Sum Problem为例,Sample Input 1 100 Sample Out
20、put 15050,2018/9/4,43,菜鸟之伤(5),#include void main() int i,n,s;while(scanf(“%d”, ,2018/9/4,44,菜鸟之伤(5),总结:忘记变量的初始化是典型的菜鸟问题,不必紧张,多经历几次就牢记了说明:普通变量的初始化还比较容易查找,而用来保存计算结果的数组的初始化更是容易忘记!,2018/9/4,45,菜鸟之伤(6),#include void main() int i,n,s=0;while(scanf(“%d”, ,2018/9/4,46,菜鸟之伤(6),总结:变量初始化放在循环外,是一个典型的ACM初级错误,因为A
21、CM赛题的多组测试特性,如果不能在循环内初始化,将只能确保第一组数据没问题,而很多入门者习惯只测试一组数据,很容易忽略这个问题。说明:菜鸟常犯的错误,关键是要理解为什么这样会有问题,真正理解后,修改也就不难了。,2018/9/4,47,菜鸟之伤(7),#include void main() int i,n,s; while(scanf(“%d”, ,2018/9/4,48,菜鸟之伤(7),总结:数组越界还能在提交后收到Runtime Error的信息反馈,而运算中的数据溢出则往往只能收到Wrong Answer的错误提示,所以这种错误往往容易被误导成算法问题;说明:不仅菜鸟,就是大牛甚至大神
22、,也常常犯这种错误,只是情况复杂些而已,2018/9/4,49,菜鸟之伤(8),#include void main() int i,n,s; while(scanf(“%d”, ,2018/9/4,50,菜鸟之伤(8),总结:当两个整数进行运算的时候,运算结果一定还是整数,所以不要因为常规数学惯性思维的影响而认为结果可能为浮点数;而不同数据类型一同运算的时候,运算结果的数据类型和相对复杂的类型一致(比如 整数+实数,结果类型是实数),2018/9/4,51,菜鸟之伤(9),#include void main() int i,n,s;while(scanf(“%d”, ,2018/9/4,5
23、2,菜鸟之伤(9),总结:写for或者while等任何循环语句的时候,不管循环体内有几个语句,务必养成都加上一对大括号的好习惯。 常常碰到的情况是这样的本来循环体内只有一条语句,确实不用大括号,但是在修改程序的过程中,循环体内增加了其他语句,而这时却忘记了添加大括号! 所以说好习惯很重要!,2018/9/4,53,菜鸟之伤(10),#include void main() int i,n,s;while(scanf(“%d”, ,2018/9/4,54,菜鸟之伤(10),总结:这也是一个经典错误,虽然为循环体加了大括号,但是并没有包含全部的信息,造成的后果是只有一次输出尽管对于每组数据都处理了
24、,但是只输出最后一组结果。 由于很多同学习惯每次只测试一组数据,就更容易忽略这个错误了. 再次证明好习惯很重要!,2018/9/4,55,菜鸟之伤(11),假设不会中间溢出,下面的程序是否有问题? #include void main() int i,n,s;while(scanf(“%d”, ,2018/9/4,56,菜鸟之伤(11),总结:这也是受数学习惯影响而可能出现的一个错误,当然,这个错误很好检查,因为编译不能通过的 总结出这个只是因为确实会出现这个情况,而对于极度没有编程经验的同学来说,有时候也会带来困扰,2018/9/4,57,还是以AB为例,题目描述:计算AB的值,输入数据每行
25、包含2个正整数,如果输入数据是两个负数,则结束输入。 Sample Input 1 5 -1 -1 Sample Output 6,2018/9/4,58,菜鸟之伤(12),#include void main() int a,b; while(scanf(“%d%d”, ,2018/9/4,59,菜鸟之伤(12),总结:正如判断相等要用“=”一样,C语言中进行逻辑与的运算也是需要两个字符“&”,类似的逻辑或运算也是两个字符“|”,如果是单个的字符,含义就完全不同了,2018/9/4,60,菜鸟之伤(13),上一个程序的改进版: #include void main() int a,b; wh
26、ile(scanf(“%d%d”, ,2018/9/4,61,菜鸟之伤(13),总结:题目描述是负数结束输入,Sample Input最后给出的是-1,如果读题不仔细,很容易陷入思维定势,而会不加思索在程序中用-1判断,这样就真的会发生不幸的事件尽管我也认为这个陷阱有点阴,而且未必有很大意义,但是题目并没错,而你确实读题不仔细说明:算是经典的小陷阱,现在很少出现了,2018/9/4,62,菜鸟之伤(14),#include void main() int a,b; while(scanf(“%d%d”, ,2018/9/4,63,菜鸟之伤(14),总结:字符串输出的大小写问题对于菜鸟需要特别注
27、意,其实,不管是全大写、全小写,还是首字母大写,你尽管复制即可(没有电子版,另当别论),当然还要注意是否有标点符号等情况。说明:菜鸟常犯错误,稍有经验即可避免,2018/9/4,64,以1170Balloon Comes!为例,Sample Input 4 + 1 2 - 1 2 * 1 2 / 1 2,Sample Output 3 -1 2 0.50,2018/9/4,65,菜鸟之伤(15),int n,a,b,i; char p; scanf(“%d“,if( ) ,2018/9/4,66,菜鸟之伤(15),刚才程序的改进版: int n,a,b,i; char p; scanf(“%d
28、“,if( .) 是否还有问题?如何修改?,2018/9/4,67,菜鸟之伤(15),总结:字符和数字的混合输入带来的问题,也是一个常常困扰使用C语言编程的同学的经典问题,关键就是程序未能及时接收回车符,而误将回车当作下一组数据的首字母,你可以通过添加一句getchar(); 轻松解决该问题。说明:菜鸟的经典错误,如果之前没有遇到过,很难一下子反应过来,当然,遇到一次以后就不成为问题了,2018/9/4,68,2007 平方和与立方和,给定一段连续的整数,求出他们中所有偶数的平方和以及所有奇数的立方和。 Sample Input 1 3 2 5 Sample Output 4 28 20 15
29、2,2018/9/4,69,继续以AB为例,题目描述:给定2个整数A和B,如果A+B0,请输出”OK!”,否则请输出”No” Sample Input 1 5 1 -5 Sample Output OK! No,2018/9/4,70,菜鸟之伤(16),总结:题目并没有保证数据是递增的,但人往往有思维定势,而很多题目的设计就是针对这一点!不要埋怨,这种训练能很好的培养我们审慎的思维习惯。说明:这种错误经历过以后还是比较容易牢记的,所以说有时候经验很重要。,2018/9/4,71,菜鸟之伤(16),#include void main() int m,n;while(scanf(“%d%d” ,
30、 ,2018/9/4,72,菜鸟之伤(17),以下的程序输出什么? #include #include int main() int j=0;for(j=0;j5;j+)cout“j=“;printf(“%dn“,j);return 0; ,2018/9/4,73,菜鸟之伤(17),期望输出:j=0 j=1 j=2 j=3 j=4,实际输出:?,2018/9/4,74,菜鸟之伤(17),总结:在一个程序中同时使用C和C+的输出语句,很容易带来问题,原因就是输出机制不完全一样(一个不带缓冲,一个带缓冲),所以尽量避免C和C+输出语句混用。说明:这是传说中的经典错误,据说曾困扰某牛人于现场赛 :-
31、),2018/9/4,75,以2004 成绩转换 为例,题目描述:输入一个百分制的成绩t,将其转换成对应的等级,具体转换规则如下:90100为A;8089为B;7079为C;6069为D;059为E; 输出描述:对于每组输入数据,输出一行。如果输入数据不在0100范围内,请输出一行:“Score is error!”。,2018/9/4,76,菜鸟之伤(18),#include int main() int t,a;while(scanf(“%d“,2018/9/4,77,菜鸟之伤(18),总结:C语言中的case语句要求在每个case的处理后面都要跟break;(特殊需求除外),而如果因为不
32、了解或者不小心而缺少部分break;则执行的效果也许会不符合你最初的设计。说明:C语言的基本功很重要,2018/9/4,78,以2046 骨牌铺方格 为例,题目描述:在2n的一个长方形方格中,用一个1 2的骨牌铺满方格,输入n ,输出铺放方案的总数. 输入描述:输入数据由多行组成,每行包含一个整数n,表示该测试实例的长方形方格的规格是2n (0n=50)。,2018/9/4,79,菜鸟之伤(19),#include int main() int i;_int64 a50=0,1,2;for(i=3;i=50;i+)ai=ai-1+ai-2;while(scanf(“%d“, ,2018/9/4
33、,80,菜鸟之伤(19),总结:数组下标越界是最常见的Runtime Error,也是菜鸟常犯的错误,除了需要扎实的C语言基本功,编程中的注意力集中也是需要的(很多时候不是不知道理论,而是不注意) 说明:一般情况,你可以通过将数组开的大点而尽量避免这个问题,2018/9/4,81,以1425 Sort为例,题目描述:给你n个整数,请按从大到小的顺序输出其中前m大的数。 输入描述:每组测试数据有两行,第一行有两个数n,m(0n,m1000000),第二行包含n个各不相同,且都处于区间-500000,500000的整数。,2018/9/4,82,菜鸟之伤(20),#include void mai
34、n() int n,m,i,num1000000;while(scanf(“%d%d”,&n,&m)=2) ,2018/9/4,83,菜鸟之伤(20),总结:ACM编程中,使用很大的数组是很常见的做法,但如果超大的数组被定义成局部变量,则很容易出现Runtime Error,解决办法也很简单:定义成全局变量即可。原因是局部变量分配在栈(较小),全局变量分配在堆(较大);说明:这里所说的超大也不能无限制的大,可以根据题目的内存限制进行估算,2018/9/4,84,以3199 Hamming Problem为例,题目描述:For each three prime numbers p1, p2 an
35、d p3, lets define Hamming sequence Hi(p1, p2, p3), i=1, . as containing in increasing order all the natural numbers whose only prime divisors are p1, p2 or p3. For example, H(2, 3, 5) = 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, . So H5(2, 3, 5)=6. 输出描述:The output file must contain the
36、 single integer - Hi(p1, p2, p3). All numbers in input and output are less than 1018.,2018/9/4,85,菜鸟之伤(21),典型错误 没有仔细分析. 也不敢尝试. 直接被吓走了,2018/9/4,86,菜鸟之伤(21),总结:这个题目从本质上来说,和1058Humble Numbers是一样的,唯一吓人的就是数据范围的描述,可能会有人想: i 这么大,没法开数组呀? 但是,你仔细分析一下会发现:因为输出也是小于1018,而同时,即使一组内的三个素数是最小的2,3,5,增长的速度也是很快的,所以不必为数组太大而着急。 当然,也不必因为发现i很小而觉得数据太水,那是因为只能如此,不然输出就要超范围了,