ACM程序设计实践指导书

这是我们学校大二计算机大类的ACM实习指导书,主要目的训练编程,用到数据结构、算法等知识,当然,必须得知道一门编程语言,我那时只会c语言,其实经过这个训练也可以参加一些竞赛。像蓝桥杯这个竞赛就类似这种题目。

在我博客里会有这些题目的题解,大家感兴趣或者需要的可以去看看。

ACM程序设计实践指导书

一、概述

ACM国际大学生程序设计竞赛由国际计算机学会(ACM)主办,是世界上公认的规模最大、水平最高的国际大学生程序设计竞赛。竞赛旨在展示大学生创新能力、团队精神和在压力下编写程序、分析和解决问题能力,素来被冠以“程序设计的奥林匹克”的尊称,已经成为风靡全球的程序设计竞赛。赛事由各大洲区域赛和全球总决赛两个阶段组成。竞赛规定每支参赛队伍由三至四名在校大学生组成,他们需要在规定的5个小时内解决10个到13个复杂实际编程问题。每队使用一台电脑,最后的获胜者为正确解答题目最多和总用时间最少的队伍。该项赛事是目前国内高校承办的唯一一项具有国际影响的计算机竞赛。

ACM程序设计主要内容为数据结构、程序设计方法、算法设计与分析学等相关课程中典型问题的编程实现。数据结构中稍微复杂一些的算法设计中可能同时要用到多种技术和方法,如算法设计的构思方法,动态变量及链表,算法的编码,递归技术,与特定问题相关的技术等。通过实验内容的训练,突出构造性思维训练的特征,提高学生组织数据与进行编写大型程序能力。上机实习是对学生的一种全面综合训练,是与课堂听讲、自学和练习相辅相成的必不可少的一个教学环节。通常,实习题中的问题比平时的习题复杂得多,也更接近实际。实习着眼于原理与应用的结合点,使读者学会如何把书上学到的知识用于解决实际问题,培养软件工作所需要的动手能力;另一方面,能使书上的知识变“活”,起到深化理解和灵活掌握教学 内容的目的。平时的上机练习较偏重于如何编写功能单一的“小”算法,而通过ACM程序设计实践,可以提高问题分析,总体结构设计,用户界面设计,程序设计基本技能和技巧。

每个实习题采取了统一的格式,由问题描述基本要求测试数据实现提示几个部分组成。

问题描述旨在为读者建立问题提出的背景环境,指明问题“是什么”;
基本要求则对问题进一步求精,划出问题的边界,指出具体的参量或前提条件,并规定该题的最低限度要求;

测试数据部分旨在为检查学生上机作业提供方便,在完成实习题时应自己设计完整和严格的测试方案,当数据输入量较大时,提倡以文件形式向程序提供输入数据;

实现提示对实现中的难点及其解法思路等问题作了简要提示;


二、实习步骤

扫描二维码关注公众号,回复: 2061851 查看本文章

随着计算机性能的提高,它所面临的软件开发的复杂度也日趋增加。然而,编制一个10000行的程序的难度绝不仅仅是一个5000行的程序的两倍,因此软件开发需要系统的方法。一种常用的软件开发方法,是将软件开发过程分为分析、设计、实现和维护四个阶段。我们制订了如下所述完成实习的5个步骤:

1.问题分析和任务定义
   通常,实习题目的陈述比较简洁,或者说是有模棱两可的含义。因此,在进行设计之前,首先应该充分地分析和理解问题,明确问题要求做什么,限制条件是什么。注意:本步骤强调的是做什么,而不是怎么做。对问题的描述应避开算法和所涉及的数据类型,而是对所需完成的任务做出明确的回答。例如:输入数据的类型、值的范围以及输入的形式;输出数据的类型、值的范围及输出的形式;若是会话式的输入,则结束标志是什么,是否接受非法的输入, 对非法输入的回答方式是什么等等。这一步还应该为调试程序准备好测试数据,包括合法的输入数据和非法形式输入的数据。

2.数据类型和算法设计
   在设计这一步骤中需分逻辑设计和详细设计两步实现。逻辑设计指的是,对问题描述中 涉及的操作对象定义相应的数据类型,并按照以数据结构为中心的原则划分模块,定义主程序模块和各抽象数据类型;详细设计则为定义相应的存储结构并写出各过程和函数的伪码算法。在这个过程中,要综合考虑系统功能,使得系统结构清晰、合理、简单和易于调试,抽象 数据类型的实现尽可能做到数据封装,基本操作的规格说明尽可能明确具体。作为逻辑设计的结果,应写出每个抽象数据类型的定义(包括数据结构的描述和每个基本操作的规格说 明),各个主要模块的算法,并画出模块之间的调用关系图。详细设汁的结果是对数据结构和 基本操作的规格说明做出进一步的求精,写出数据存储结构的类型定义,按照算法书写规范函数形式的算法框架。在求精的过程中,应尽量避免陷入语言细节,不必过早表述辅助数据结构和局部变量。

3.编码实现和静态检查

编码是把详细设计的结果进一步求精为程序设计语言程序。如何编写程序才能较快地完成调试是特别要注意的问题。对于编程很熟练的读者,如果基于详细设计的伪码算法就能直接在键盘上输入程序的话,则可以不必用笔在纸上写出编码,而将这一步的工作放在上机准备之后进行,即在上机调试之前直接用键盘输入。

然而,不管是否写出编码的程序,在上机之前,认真的静态检查却是必不可少的。多数初学者在编好程序后处于以下两种状态之一:一种是对自己的“精心作品”的正确性确信不疑;另一种是认为上机前的任务已经完成,纠查错误是上机的工作。这两种态度是极为有害的。事实上,非训练有素的程序设计者编写的程序长度超过50行时,极少不含有除语法错误以外的错误。上机动态调试决不能代替静态检查,否则调试效率将是极低的。静态检查主要有两种方法,一是用一组测试数据手工执行程序(通常应先分模块检查);二是通过阅读或给别人讲解自己的程序而深入全面地理解程序逻辑,在这个过程中再加入一些注解和断言。如果程序中逻辑概念清楚,后者将比前者有效。

4.上机准备和上机调试

上机准备包括以下几个方面:

(1) 熟悉机器的操作系统和语言集成环境的用户手册,尤其是最常用的命令操作,以便顺利进行上机的基本活动。

(2)  掌握调试工具,考虑调试方案,设计测试数据并手工得出正确结果。“磨刀不误砍柴工”。计算机各专业的学生应该能够熟练运用高级语言的程序调试器DEBUG调试程序。

(3)   ACM实践题请登录PKU Judge Online提交程序并调试。

调试最好分模块进行,自底向上,即先调试低层过程或函数。在调试过程中可以不断借助DEBUG的各种功能,提高调试效率。调试中遇到的各种异常现象往往是预料不到的,此时不应“苦思具想”,而应动手确定疑点,通过修改程序来证实它或绕过它。调试正确后,认真整理源程序及其注释。

 

5.总结和整理实习报告


三、基础性题目

实习要求:

本次实习题目分为三大部分,第一部分为基础问题、第二部分为经典算法问题、第三部分为ACM实践题。其中,第一部分为基础必做题,要求每人从8道题目中任选5道题完成;第二部分是选做题,可以选做其中任何一题,完成情况作为学生总评成绩优秀的参考;第三部分ACM实践题,要求必做至少3题(超过可获得总评良好以上),除了要完成基本的分析外,需要在实践报告中注明自己的账号,程序AC截图等,并将题目翻译成流畅易读的中文格式鼓励多选题目。

实习最后一天(12周周五)为程序检查,所有同学必须将程序运行给指导老师看,指导老师可就实习内容进行提问,不参加程序检查的同学,成绩为不及格。实习结束后,每位同学独立撰写一篇实习报告,用A4纸打印,以班为单位按学号排列收齐交给老师。不交实习报告的,成绩为不及格。实习成绩由指导老师根据程序运行情况、实习报告质量、平时考勤综合评定。

 

 

第一部分:基础问题

 

1.1【问题描述】

出题给小学生做,每次考试的题数可以设定,随机产生n个题目,将题目及标准答案写入文件中;题目涉及加减乘除,带括弧的混合运算;根据答题情况给出分数;将学生的学号,每道题的答案,分数也写入文件中,即每个学生的考试情况放在一个文件中保存。

一个算式的求值:求一个可能包含加、减、乘、除运算的中缀表达式的值。在计算机中,我们常用栈来解决这一问题。首先将中缀表达式转换到后缀表达式,然后对后缀表达式求值。加、减、乘、除分别用+-*, /,来表示。表达式可以有圆括号()。每个表达式中,圆括号、运算符和运算数相互之间都用空格分隔,运算数是整数,考虑除数为0的情况,除法的商向下取整。

 

【测试数据】

【输入范例】2 * 5 + 6 * ( 7 - 8 ) +6          

【输出范例】10

【实现提示】

(1) 在程序中会用到两类栈:操作数栈和运算符栈,分别为整型数据和字符型数据,设置运算符栈和操作数栈辅助分析算符优先关系;

(2) 在读入字符序列时,完成运算符和操作数的处理,以及相应运算;

(3) 算符之间的优先关系可参考数据结构教材

 

1.2 【问题描】

17世纪法国数学家加斯帕在《数学的游戏问题》中讲的一个故事:n个教徒和n个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了个办法:2n个人围成一个圆圈,从第一个人开始依次循环报数,每数到第九个人就将他扔入大海,如此循环直到仅剩n个人为止。问怎样的排法,才能使每次投入大海的都是非教徒。   

【输入】  输入文件由一行构成,就是n的值。 

【输出】  输出文件中是一行字符串,字符串由n‘@’字符(代表教徒)和n‘+’ 字符(代表非教徒)排列构成。该排列使得按照前面的约定每次投入大海的都是非教徒。  

 

【输入范例】  15  

【输出范例】 @@@@+++++@@+@@@+@++@@+++@++@@+

 

1.3【问题描述】 

我们要求找出具有下列性质数的个数(包含输入的自然数n)。先输入一个自然数n(n<=1000),然后对此自然数按照如下方法进行处理: 1.不作任何处理; 2.在它的左边加上一个自然数,但该自然数不能超过原数最高位数字的一半; 3. 加上数后,继续按此规则进行处理,直到不能再加自然数为止. 

 

【输入】  第一行一个数t,表示有t组数据 之后每组数据占一行,每行一个数n 

【输出】  每组数据占一行,一个数,表示满足条件的数的个数 

【输入范例】1 6 

【输出范例】6

1.4【问题描述】

用给定的几种钱币凑成某个钱数,一般而言有多种方式。例如:给定了6种钱币面值为2、5、10、20、50、100,用来凑 15元,可以用5个2元、1个5元,或者3个5元,或者1个5元、1个10元,等等。显然,最少需要2个钱币才能凑成15元。  你的任务就是,给定若干个互不相同的钱币面值,编程计算,最少需要多少个钱币才能凑成某个给出的钱数。

  

【输入】  可以有多个测试用例。每个测试用例的第一行是待凑的钱数值M(1 <= M <= 2000,整数),接着的一行中,第一个整数K(1<= K <= 10)表示币种个数,随后是K个互不相同的钱币面值Ki(1 <= Ki <= 1000)。输入M=0时结束。

【输出】  每个测试用例输出一行,即凑成钱数值M最少需要的钱币个数。如果凑钱失败,输出“Impossible”。你可以假设,每种待凑钱币的数量是无限多的。  

 

【输入范例】 15  6 2 5 10 20 50 100 1 1 20  

【输出范例】 2  Impossible

1.5【问题描述】

蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。  

【输入】  本题有多组数据,每组数据由一个正整数N组成。(N不大于100) 

【输出】  对于每一组数据,输出一个N行的蛇形矩阵。两组输出之间不要额外的空行。矩阵三角中同一行的数字用一个空格分开。行尾不要多余的空格。

【输入范例】5   

【输出范例】 1 3 6 10 15 2 5 9 14 4 8 13 7 12 11

 

1.6【问题描述】

输出7 和7 的倍数,还有包含7 的数字例如(17,27,37...70,71,72,73...)

【输入】  一个整数N。(N 不大于30000)

【输出】  从小到大排列的不大于N 的与7 有关的数字,每行一个。

【输入范例】20

【输出范例】7   14  17

1.7【问题描述】

第四平方和定理,又称为拉格朗日定理:每个正整数都可以表示为至多4个正整数的平方和。  如果把0包括进去,就正好可以表示为4个数的平方和。比如:5 = 0^2 + 0^2 + 1^2 + 2^2 7 =1^2 + 1^2 + 1^2 + 2^2 (^符号表示乘方的意思)对于一个给定的正整数,可能存在多种平方和的表示法。 要求你对4个数排序:0 <= a <= b <= c <= d  并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法 

【输入】  一个正整数N (N<5000000) 

【输出】  4个非负整数,按从小到大排序,中间用空格分开 

输入范例1】 5 

输出范例1】0 0 1 2 

输入范例2】773535

输出范例2】1 1 267 838

1.8【问题描述】

有一长度为N(1<=N<=10)的地板,给定两种不同瓷砖:一种长度为1,另一种长度为2,数目不限。要将这个长度为N的地板铺满,一共有多少种不同的铺法?

例如,长度为4的地面一共有如下5种铺法:

4=1+1+1+1

4=2+1+1

4=1+2+1

4=1+1+2

4=2+2

编程用递归的方法求解上述问题。

【输入】  只有一个数N,代表地板的长度

【输出】  输出一个数,代表所有不同的瓷砖铺放方法的总数 

输入范例】  4

【输出范例】  5

 

第二部分:经典算法

1.     分治与递归

编写自然归并合并排序算法

算法描述:对于初始给定的数组,通常存在多个长度大于1的已自然排好序的子数组段.例如,若数组a中元素为{4,8,3,7,1,5,6,2},则自然排好序的子数组段有{4,8},{3,7},{1,5,6},{2}.用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段.然后将相邻的排好序的子数组段两两合并,构成更大的排好序的子数组段({3,4,7,8},{1,2,5,6}).继续合并相邻排好序的子数组段,直至整个数组已排好序。

2.     动态规划

0-1背包问题:若有物品n个,每个物品的价值Value,用vi表示,每个物品的重量weight用wi表示,其中vi和wi均为非负数。设背包的总容量为W,且W为非负数。现需要考虑的问题是:如何选择装入背包的物品,使装入背包的物品总价值最大。

第一步,刻画问题的最优解子结构。可以将背包问题的求解过程看作是进行一系列的决策过程,即决定哪些物品应该放入背包,哪些物品不放入背包。如果一个问题的最优解包含了物品n,即xn=1,那么其余x1,x2,...,x(n-1)一定构成子问题1,2,...,n-1在容量W-wn时的最优解。如果这个最优解不包含物品n,即xn=0,那么其余x1,x2,...,x(n-1)一定构成子问题1,2,...,n-1在容量W时的最优解。

第二步,递归定义最优解的值,根据上述分析的最优解的结构递归地定义问题最优解。设G【i,w】表示背包容量为w时,i个物品导致的最优解的总价值,得到下式。显然要求G【n,w】:

3.     贪心算法

问题陈述:

给定n种物品和一个背包.物品i的重量是Wi,其价值为Vi,背包的容量为C.在选择物品i装入背包时,可以选择物品i的一部分,1<=i <=n.问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大.

贪心选择性质:
若vi/wi ≥vi+1/wi+1 ,1≤i≤n-1,则存在背包问题的一个最优解(x1,x2,…xn),使得x1 =min {W/ w1 ,1}。
分三种情况证明背包问题的这个贪心选择性质
(1)∑wi ≤W ,此时唯一的最优解为(x1,x2,…xn)。
(2)∑wi >W ,且vi/wi =v1/w1 ,2≤i≤n ,则它的每一个解跟最优解相同
(3)∑wi >W ,S=(x1,x2,…xn),S包含于{,x2,…xn}使得x1∈S。
事实上,设S包含于{,x2,…xn } 是背包问题的一个最优解,且x1不属于S。对任意i∈S,取Si =S∪{ x1}-{ xi },则Si 满足贪心选择性质的最优解。
这两类问题都具有最优子结构性质,极为相似,但背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解.

最优子结构性质:

对于背包问题,若它的一个最优解包含物品j,则从该最优解中拿出所含的物品j的那部分重量w,剩余的将是n-1个原重物品1,2,…,j-1,j+1,…,n及重为Wj-W的物品j中可装入容量为c-w的背包且具有最大价值的物品.

4.     回溯法与分支限界法

八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

第三部分ACM程序实践题

 

请在北大JudgeOnline注册账号,http://poj.org/problemlist,从题库中选择不少于3个问题,要求全部选择英文题目,其中通过率(Ratio)为50%以下的题目。

四、实习报告规范

实习报告的开头应给出题目、班级、姓名、学号和完成日期,并包括以下7个内容:
1
.需求分析
以无歧义的陈述说明程序设计的任务,强调的是程序要做什么?并明确规定:
(1) 输入的形式和输入值的范围;
(2) 输出的形式;
(3) 程序所能达到的功能;
(4) 测试数据:包括正确的输入及其输出结果和含有错误的输入及其输出结果。
2
.概要设计
说明本程序中用到的所有抽象数据类型的定义、主程序的流程以及各程序模块之间的层次(调用)关系。
3
.详细设计
实现概要设计中定义的所有数据类型,对每个操作只需要写出伪码算法;对主程序和其他模块也都需要写出伪码算法(伪码算法达到的详细程度建议为:按照伪码算法可以在计算机键盘直接输入高级程序设计语言程序);画出函数和过程的调用关系图。
4
.调试分析
内容包括:
a.调试过程中遇到的问题是如何解决的以及对设计与实现的回顾讨论和分析;
b.算法的时空分析(包括基本操作和其他算法的时间复杂度和空间复杂度的分析)和改进设想;
c.经验和体会等。
5
.用户使用说明
说明如何使用你编写的程序,详细列出每一步的操作步骤。
6
.测试结果
列出你的测试结果,包括输入和输出。这里的测试数据应该完整和严格,最好多于需求分析中所列。
7
.附录
带注释的源程序。如果提交源程序软盘,可以只列出程序文件名的清单。


 

实验报告示例

__________ __________ ___________________
姓名____________ 学号____________

1.实验题目

编制一个演示单链表插入、删除、查找等操作的程序

2.需求分析

本演示程序用TC编写,完成单链表的生成,任意位置的插入、删除,以及确定某一元素在单链表中的位置。
输入的形式和输入值的范围:插入元素时需要输入插入的位置和元素的值;删除元素时输入删除元素的位置;查找操作时需要输入元素的值。在所有输入中,元素的值都是整数
输出的形式:在所有三种操作中都显示操作是否正确以及操作后单链表的内容。其中删除操作后显示删除的元素的值,查找操作后显示要查找元素的位置。
程序所能达到的功能:完成单链表的生成(通过插入操作)、插入、删除、查找操作
测试数据:
A
插入操作中依次输入111213141516,生成一个单链表
B
查找操作中依次输入121522返回这3个元素在单链表中的位置
C
删除操作中依次输入25,删除位于25的元素

3.概要设计

1)为了实现上述程序功能,需要定义单链表的抽象数据类型:
ADT LinkList {
数据对象:D={ai|aiIntegerSet,i=0,1,2,…,n,n≥0}
数据关系:R={<ai,ai+1>|ai,ai+1 D}
基本操作:
InitLinkList(&L)
操作结果:构造一个空的单链表L.
InsLinkList(&L,pos,e)
初始条件:单链表L已存在
操作结果:将元素e插入到单链表Lpos位置
DelLinkList(&L,pos,&e)
初始条件:单链表L已存在
操作结果:将单链表Lpos位置的元素删除,
元素值置入e中返回
LocLinkList(L,e)
初始条件:单链表L依存在
操作结果:单链表L中查找是否元素e
若存在,返回元素在表中的位置;若不存在,返回-1.
Menu()
操作结果:在屏幕上显示操作菜单

2)本程序包含7个函数:
主函数main()
初始化单链表函数InitLinkList()
显示操作菜单函数menu()
显示单链表内容函数dispLinkList()
插入元素函数InsLinkList()
删除元素函数DelLinkList()
查找元素函数LocLinkList()

各函数间关系如下:

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。对主程序和其他模块也都需要写出伪码算法。
1)
结点类型和指针类型
typedef struct node {
int data;
struct node *next;
}Node,*LinkListl;

2)单链表的基本操作

为了方便,在单链表中设头结点,其data域没有意义。

boolInitLinkList(LinkList &L)
(伪码算法)
void DispLinkList(LinkList L)
(伪码算法)
void menu()
(伪码算法)
bool InsLinkList(LinkList &L,int pos,int e)
(伪码算法)
bool DelLinkList(LinkList &L,int pos,int &e)
(伪码算法)
int LocLinkList(LinkList L,int e)
(伪码算法)

3)其他模块伪码算法

5.调试分析
(
)

6.使用说明

程序名为LinkList.exe,运行环境为DOS。程序执行后显示
========================
0----EXIT
1----INSERT
2----DELETE
3----LOCATE
=======================
SELECT:

select后输入数字选择执行不同的功能。要求首先输入足够多的插入元素,才可以进行其他的操作。每执行一次功能,就会显示执行的结果(正确或错误)以及执行后单链表的内容。

选择0:退出程序
选择1:显示“INSERT pos,e =”
要求输入要插入的位置和元素的值(都是整数)。
选择2:显示“DELETE pos =”
要求输入要删除元素的位置,执行成功后返回元素的值。
选择3:显示“LOCATE e = ”
要求输入要查找元素的值,执行成功后返回元素在表中的位置

7.测试结果

1) 建立单链表:
» 选择1,分别输入(0,11),(0,12),(0,13),(0,14)(0,15)。得到单链表(15,14,13,12,11)
2)插入:
» 选择1输入(1,100),得到单链表(15,100,14,13,12,11)
» 选择1输入(-1,2),显示输入错误
» 选择1输入(7,2),显示输入错误
» 选择1输入(6,2),得到单链表(15,100,14,13,12,11,2)
3)删除:
» 选择2,输入1。返回e=100,得到单链表(15,14,13,12,11,2)
» 选择2,输入0。返回e=15,得到单链表(14,13,12,11,2)
» 选择2,输入4。返回e=2,得到单链表(14,13,12,11)
» 选择2,输入5。返回输入错误
4)查找
» 选择3,输入14。返回pos=0
» 选择3,输入100。返回输入错误

猜你喜欢

转载自blog.csdn.net/qq_41045071/article/details/80964898