清华大学ACM/icpc集训队2007.3.251清华大学ACM集训队培训资料(内部使用)一、C++基础基本知识所有的C++程序都是有函数组成的,函数又叫做子程序,且每个C++程序必须包含一个main函数,编译器(能够把源代码转换成目标代码的程序)把翻译后的目标代码和一些启动代码组合起来,生成可执行文件,main函数就是可执行文件的入口,所以,每个C++程序有且只有一个main函数。下面我们看一个最简单C++程序。(程序1.1)程序1.1intmain(){return0;}在这个程序中,如果缺少任何一个字符,编译器就无法将其翻译成机器代码。此外,C++是对大小写敏感的,这就意味着,如果我将mian()函数拼为Main(),哪么,编译器在编译这段程序的时候就会出错。编辑源文件能够提共管理程序开发的所有步骤,包括编辑的程序成为集成开发环境(integrateddevelopmentevironments,IDE)。在windows系统下,使用较为广泛的有MicrosoftVisualC++、Dev-Cpp等,在UNIX系统下,有Vim、emacs、eclipes等。这些程序都能提供一个较好的开发平台,使我们能够方便的开发一个程序,接下我们所要了解的都是标准C++,所有源代码都在Dev-cpp下编写,能够编译通过。如果我们修改程序1.1中的main()函数的名称,将其改为Main(),那么,IDE就会给出错误信息,比如“[Linkererror]undefinedreferenceto`WinMain@16'”,因为编译器没有找到main函数。接下来,我们来看一个经典的C++例子(程序1.2)程序1.2#includeiostreamusingnamespacestd;intmain(void){coutHelloWrold!endl;return0;}运行结果HelloWorld!程序说明第一行“#includeiostream”,是一句预处理命令,相当于把“iostream”这个文件的所有内容复制到当前位置,替换该行。因为在输出操作中需要做很多事,C++编译器就提供了清华大学ACM/icpc集训队2007.3.252很多已经写好的函数(成为C++标准库),我们做的只是拿来用就可以了。第二行的“usingnamespacestd;”是使用标准命名空间,因为我们在程序中用到了在标准命名空间里的函数和对象。目前可以不了解其具体如何实现,在以后的程序设计中可以再对其进行了解。在明函数中“cout”HelloWorld!”endl;”是在屏幕上打印“HelloWorld!”,“endl”表明打印完这句话之后需要换行。如果我们替换引号内的内容,程序的输出就会相应改变。另外一个C++程序例子//ourfunc.cpp--definingyourownfunction#includeiostreamvoidsimon(int);//functionprototypeforsimon()intmain(){usingnamespacestd;simon(3);//callthesimon()functioncoutPickaninteger:;intcount;cincount;simon(count);//callitagaincoutDone!endl;return0;}voidsimon(intn)//definethesimon()function{usingnamespacestd;coutSimonsaystouchyourtoesntimes.endl;}//voidfunctionsdon'tneedreturnstatements下面试运行情况:Simonsaystouchyourtoes3times.Pickaninteger:512Simonsaystouchyourtoes512times.Done!程序中包含了cin语句来从键盘上获取数据。该程序中包含了除main函数以外的另一个函数simon(),他和main函数定义的格式相同,函数的统一格式如下:typefunctionname(argumentlist){statements}注意,定义simon()的代码在main()函数的后面,C++中不允许将函数定义在另一个函数内。每个函数的定义都是独立的,所有的函数的创建都是平等的。simon()函数的函数头定义如下:清华大学ACM/icpc集训队2007.3.253voidsimon(intn)以void开头表明simon()没有返回值,因此我们不能类是这样的使用它。simple=simon(3);有返回值的函数如下//convert.cpp--convertsstonetopounds#includeiostreamintstonetolb(int);//functionprototypeintmain(){usingnamespacestd;intstone;coutEntertheweightinstone:;cinstone;intpounds=stonetolb(stone);coutstonestone=;coutpoundspounds.endl;return0;}intstonetolb(intsts){return14*sts;}下面是运行情况:Entertheweightinsone:1414stone=196pounds.程序通过cin语句给stone提供一个值,然后在main函数中,把这个值传递给stonetolb()函数,这个植被赋给sts之后,stonetolb()用return将14*sts返回给main()。函数头中的int表明stonetolb()将返回一个整数。除了int类型之外,C++的内置数据类型还有:unsignedlong、long、unsignedint、unsignedshort、short、char、unsignedchar、signedchar、bool、float、double、longdouble。对于数据的输入和输出有几道练习题=1089至=1096二、算法基础1.什么是算法算法是完成特定任务的有限指令集。所有的算法必须满足下面的标准:a.输入。由外部题共零个或多个输入量。清华大学ACM/icpc集训队2007.3.254b.输出。至少产生一个输出量。c.明确性。每条指令必须清楚,不具模糊性。d.有限性。如果跟踪算法的指令,那么对于所有的情况,算法经过有限步以后终止。e.有效性。每条指令必须非常基础,原则上使用笔和纸就可以实现例选择排序voidSelectionSort(Typea[],intn)//Sortthearrata[1:n]intonondecreasingorder.{for(inti=1;i=n;i++){intj=1;for(intk=i+1;k=n;k++)if(a[k]a[j])j=k;Typet=a[i];a[i]=a[j];a[j]=t;}}使用该函数时,应将Type替换为C++中的数据类型3.性能分析程序P所用时间定义为T(P),T(P)是编译时间和运行时间之和。下面我们计算一下选择排序运行时所要花费的时间SelectionSortcosttimesfor(inti=1;i=n;i++)c1n{intj=1;c2nfor(intk=i+1;k=n;k++)c3)(1niinif(a[k]a[j])c4)(1niinj=k;c5itTypet=a[i];a[i]=a[j];a[j]=t;c6n}清华大学ACM/icpc集训队2007.3.255那么该算法运行的时间nctcincincncncnTinini65141321)()(那么,在最坏的条件下,it的值应该是)(1niin所以,算法的运行时间为25435434621)(21)212121(ncccnccccccnT4.渐进符号定义:[大O]函数))(()(ngOnf,念做)(nf是)(ng的大”oh”,当且仅当存在正常数c和0n,使得对于所有的)(0nnn,有)()(ngcnf。例对于所有2n有nn423,所以)(23nOn。对于所有6n有nn1016100,所以)(6100nOn对于所有100n有22100161001000nnn,所以)(6100100022nOnn当然对于所有2n有421024100nnn,所以)(241042nOnn定义:[Ω]函数))(()(ngnf,念做)(nf是)(ng的”omega”,当且仅当存在正常数c和0n,使得对于所有的)(0nnn,有)()(ngcnf。例对于所有1n有nnn2262,所以)2(262nnn。当然)(262nnn,但是)2()(nn。现然无论是O还是Ω,都不能精确的描述一个函数定义:[Θ]函数))(()(ngnf,念做)(nf是)(ng的”theta”,当且仅当存在正常数21,cc和0n,使得对于所有的)(0nnn,有)()()(21ngcnfngc。例对于2n有nn323且nn423,所以)(23nn清华大学ACM/icpc集训队2007.3.256Θ记号要比O和Ω都要精确。排列生成器Θ(n!)voidPerm(Typea[],intk,intn){if(k==n){//Outputpermutation.for(inti-1;in;i++)couta[i];}else//a[k:n]hasmorethanonepermutation.//Generatetheserecursively.for(inti=k;i=n;i++){Typet=a[k];a[k]=a[i];a[i]=t;Perm(a,k+1,n);//Allpermutationsofa[k+1:n]t=a[k];a[k]=a[i];a[i]=t;}}对于下面的程序#includeiostreamusingnamespacestd;voidPerm(inta[],intk,intn){if(kn-1){inti,t;for(i=k;in;i++){t=a[k];a[k]=a[i];a[i]=t;Perm(a,k+1,n);t=a[k];a[k]=a[i];a[i]=t;}}else{inti;for(i=0;in;i++){couta[i]'\t';}coutendl;}}intmain(void){inta[3]={1,2,3};Perm(a,0,3);return0;}该程序的运行结果为123132213231321312清华大学ACM/icpc集训队2007.3.257那么,该函数就完成了对一个数组进行全排列的操作下面,分析该程序,我用圆圈代表每次函数的调用每次函数的调用都用序号表示1.a:123k:02.a:123k:13.a:123k:24.a:132k:25.a:213k:16.a:213k:27.a:231k:28.a:321k:19.a:321k:210.a:312k:2排列生成器的另外一个版本他将输出给定n个布尔变量的所有可能的组合voidPerm(boola[],intk,intn){if(k==n){//statement}else{a[k]=true;Perm(a,k+1,n);a[k]=false;Perm(a,k+1,n);}}在上次冬季赛上有这么一道题竞赛真理JUNNY在经历了无数次学科竞赛的失败以后,得到了一个真理:做一题就要对一题