学数学的时候,我们通常会通过大量的练习题来巩固所学知识;其实学习程序设计设计语言也不例外。那么如何通过练习去磨砺自己的C#使用能力呢?一个方法是参与到实际的软件项目开发中,而另一个更加直接的方法则是“做题”。
去哪里找练习题呢?听过或接触过ACM/ICPC(http://cm.baylor.edu)的读者,应该不会对Online Judge(http://en.wikipedia.org/wiki/Online_judge)(以下简称OJ)陌生。OJ是一个在线评测平台,包含了大量的程序设计题目,在这个平台上用户可以提交源代码,OJ会对其进行编译和执行,并通过预定义的测试数据来验证源代码是否正确。在国内,比较有影响力的OJ有POJ(http://acm.pku.edu.cn/JudgeOnline/)和ZOJ(http://acm.zju.edu.cn/onlinejudge/)等。但可惜地是,它们只支持C、C++、Pascal、Java等,却没有给C#一席之地。尽管如此,还是有不少国外的OJ支持着C#。下面我就列举了三个优秀的在线评测平台,它们在一定程度上很好地支持了C#。
Timus Online Judge
Timus Online Judge(以下简称TOJ) 地址是 http://acm.timus.ru/。它是一个俄罗斯的在线评测平台,上面汇集了大量程序设计竞赛的套题。此外,它也是为数不多一直提供最新C#编译功能的OJ。下面是TOJ关于支持C#编译的一些历史:
- 2006年12月31日开始支持使用C#源程序提交解题程序;
- 2008年02月08日以前均在使用Microsoft Visual C# 2005编译器;
- 2009年08月04日以前均在使用Microsoft Visual C# 2008编译器;
- 2009年08月04日开始至今使用Microsoft Visual C# 2010编译器
TOJ服务器目前的C#编译命令为:
csc /o+ /d:ONLINE_JUDGE /r:System.Numerics.dll
先简单介绍一下这个编译命令什么意思。开头的csc实质上是csc.exe,它是C#编译器的名称,在安装完.NET Framework之后就可以在安装目录找到。后面跟着的一串命令“/o+ /d:ONLINE_JUDGE /r:System.Numerics.dll”是所谓的编译器参数。
- “/o”是“/optimize”的简称,该选项可以通知CLR在运行时是否优化代码。这里的“/o+”即为启用优化,它可以使得输出文件更小、更快且更有效;
- “/d”是“/define”的简称,它可以用来定义源文件中的一个或多个符号名称,功能类似于#define预指令定义一个宏。这里的“/d:ONLINE_JUDGE”就是将ONLINE_JUDGE定义为所有源代码文件中的一个符号。这样就相当于用户不需要做任何事情就可以在源程序序中直接使用ONLINE_JUDGE进行一些预处理操作;
- “/r””是“/reference”的简称,该选项可以将指定文件的public类型信息导入到当前项目中,从而可以从指定的程序集文件引用元数据。因此“/r:System.Numerics.dll”就是将System.Numerics.dll程序集导入到当前项目中。为什么非要把这个程序集导入呢?因为.NET Framework 4.0新引入的这个程序集里引入了两个非常有用的结构,它们就是BigInteger和Complex。前者可以支持任意大的带符号整数的加减乘除等运算;后者可以支持复数运算。这两个结构可以给你做题时带来极大的便利。
下面让我们一同走进TOJ,看看如何通过它来提高自己的C#使用能力。首先要做的事情就是在TOJ上注册一个账号(http://acm.timus.ru/register.aspx)。注册完毕会得到一个Judge ID,接着便可以打开“Problem Set”并挑选一道题目进行解答。以1000. A+B Problem(http://acm.timus.ru/problem.aspx?space=1&num=1000)为例:题目大意就是对给定两个数a和b,输出它们的和,要求程序必须在1秒内运行完,且最多只能使用16M的内存。读题完毕,相信大家都可以很轻松地写出如下代码:
03 | public class TOJ1000Sum |
05 | private static void Main() |
07 | string [] tokens = Console.ReadLine().Split( ' ' ); |
08 | Console.WriteLine( int .Parse(tokens[0]) + int .Parse(tokens[1])); |
点击“Sumbit solution”,选择要提交的源代码文件或者直接将源程序粘贴到文本框中、填入刚刚申请的Judge ID、选择“Language”为C#、点击“Submit”按钮之后就可以看到评测的结果了,如:
上述状态的意思是:RujinCao于2010年8月10日21点35分42秒提交了题号为1000的程序,该程序使用C#语言编写,运行时间为109毫秒,占用内存613K,最重要的是该程序通过了全部的测试数据!除了Accepted外,你还可能会常常碰到如下的返回状态:
- Compilation Error 编译错误
- Wrong Answer 程序不正确,无法通过全部的测试数据
- Time limit exceeded 程序运行时间超过了规定的时间限制
- Memory limit exceed 程序运行内存超过了规定的内存限制
- Crash 程序运行有异常
更多信息可以阅读TOJ的FAQ(http://acm.timus.ru/help.aspx?topic=faq)。
TopCoder
TopCoder网站地址为http://www.topcoder.com/tc 。它是一个美国的网站,主要以竞赛形式外包软件设计、软件开发等项目。不过这里要介绍的并不是如何开发软件,而是介绍TopCoder的算法竞赛部分。
首先打开TopCoder网站,点击右侧的“Register Now”或者直接输入网址https://www.topcoder.com/reg/ 进行注册。注册完毕,点击左上角的“O(n)”图标,并按照提示安装必要的Java组件,之后就可以下载并打开TopCoder竞技场软件(TopCoder Arena),如下图所示:
输入注册号的账号和密码,点击“GO”,会进入到竞技场的休息聊天室(Lobby Chat Room),在这里你可以和当前登录的其他用户进行聊天(TopCoder用户分布于世界各个国家)。选择菜单“Practice Rooms” –> “2. SRMs”,接着挑选要练习的一个场次,如“SRM 454 DIV2”,就可以进入到练习区域(注:SRM全称为Single Round Match。TopCoder会在每月举行4到5次的SRM在线竞赛,每场竞赛分两个级别:DIV1和DIV2,前者适合于高等级的用户,后者适合于分数较低的用户。对于初学者建议选择DIV2进行练习),如图:
接下去选择“Select one”下拉框,会看到250,500和1000的字样,这代表了此轮竞赛有三个题目,分数分别为250分,500分和1000分,分数越高,难度越大。当用户打开某一道题目之后,分数就开始自动减少,换句话说,提交源程序越快则分数越高。TopCoder允许用户多次提交同一道题目,但是每次提交都会扣取一定的分数。下面我们打开250分的题目:
阅读完题目大意“Problem Statement”后,就可以在代码区域“Coding Area”编写解答程序。要注意地是,TopCoder与普通的OJ不一样,它要求用户提交的程序的类名、方法名等必须完全符合题目中的要求。以这道250分的题来说,题目要求我们类名必须为“MinimalDifference”,方法名必须声明为“int findNumber(int A, int B, int C)”,而且必须是public类型。
这道题目大意是“给定三个整数A,B和C,要求返回区间[A,B]之间的一个数字X,使得X各位数字之和与C各位数字之和的绝对值最小,如果存在多个这样的X,返回最小的一个。其中A,B,C的范围均在[1,1000000000]之间,且保证B减去A的值在[0, 100000]之间。”
我们可以很轻松地完成下面的代码(注意:TopCoder中的.NET Framework 版本仅为2.0.50727,因此有许多C#的新特性在这里无法使用):
03 | public class MinimalDifference |
05 | private int GetDigitSum( int n) |
16 | public int findNumber( int A, int B, int C) |
18 | int sumC = GetDigitSum(C); |
19 | int minDiff = int .MaxValue; |
21 | for ( int i = A; i <= B; i++) |
23 | int sum = GetDigitSum(i); |
24 | int diff = Math.Abs(sum - sumC); |
确保“Language”选择的是“C#”,之后点击“Compile”,系统会告诉你编译是否有问题,如果没有问题,可以点击“Submit”提交源代码(注:这里还有一些其他非常还用的功能,尤其是“Test”,读者可以自行实践”)。接下去系统会在聊天区给出这次提交得到的分数,但是尽管如此,我们并不能保证提交的程序一定正确。幸好TopCoder提供了测试功能,点击菜单上的“Practice options”->“Run System Test”, 如果一切顺利,我们会看到一个绿色的分数(如图所示);否则会看到一个红色的分数,这说明源程序中有错误,需要修改。
如果读者实在无法解答某一道题目,一种方法可以通过TopCoder主页左侧栏中的“Competitions->Algorithm->Statistics->Match Editorials ”或直接输入网址http://www.topcoder.com/wiki/display/tc/Algorithm+Problem+Set+Analysis 中找到对应比赛的解题报告;另外一种方法可以打开Arena中的“Summary”功能查看其他比赛选手的代码进行学习。
TopCoder Arena功能丰富,我所介绍的只是冰山一角,更多功能期待读者们自己去发掘。
CodeForces
Code Forces地址在http://codeforces.com/ 。这是2010年刚兴起的一个在线评测网站,由俄罗斯人创建。它综合了TopCoder和普通OJ的优点:以TopCoder比赛的形式进行,以普通OJ的文件方式提交源程序。下面我将简单介绍一下如何在CodeForces上使用C#进行练习:
和前面一样,首先要做的是注册一个账号,CodeForces的注册网址为http://codeforces.com/register 。注册完毕之后,我们可以挑选一场比赛进行练习,下面以Codeforces Beta Round#25(Div. 2)为例(http://codeforces.com/contest/25)。点击右侧的“Register for practice”以注册这次练习。打开B题 Phone numbers(http://codeforces.com/contest/25/problem/B),并仔细阅读题目。大意就是:“给定一个n位的电话号码(2 ≤ n ≤ 100),将其分割成任意两位或三位的组合以方便记忆。如:7位的电话号码1198733可以分割为11-987-33或119-87-33或11-98-733,只要输出一种分割即可。”相信大家可以很轻松地完成如下的类似代码:
03 | public class Codeforces25B |
05 | public static void Main() |
07 | int n = int .Parse(Console.ReadLine()); |
08 | string phoneNum = Console.ReadLine(); |
10 | for (i = 0; i < n - 3; i += 2) |
12 | Console.Write(phoneNum.Substring(i, 2)); Console.Write( "-" ); |
14 | Console.WriteLine(phoneNum.Substring(i)); |
选择“Language”为“C# Mono 2.6+”,并选择要提交的源代码文件,点击“Submit”提交之后即可以看到结果,如下:
这里,读者们也许会有些疑问,刚刚提到的“C# Mono 2.6+”是何物,它又和微软的C#有什么关系?其实,C# Mono是微软C#的一个开源实现,它的目标是跨平台和跨语言,目前由Novell公司主持。更多关于Mono的信息请关注http://mono-project.com/Main_Page 。
当然,除了上面介绍的三个支持C#的在线评测平台以外,还有着其他一些OJ也支持C#,不过大体上做题的方式都相近,不再一一列举。为了帮助读者们更好地去了解如何在上述的三个OJ中做题,我特意创建了一个Blog(http://newacm.info/)用以跟进分析解答它们中的习题。如果大家有问题,可以直接在Blog中留言或者直接发送邮件给我(newacminfo AT gmail.com)。好了,到这里我相信读者们对使用C#“做题”练习也有了一定的认识,接下去就是你们在OJ平台上一展身手的时候了!最后希望大家都能在练习中将自己的C#使用能力磨砺的越来越精纯!