星海's Blog

老头初学编程

转贴:projecteuler vs ACM and the path

转自

http://sgxiao.blog.163.com/blog/static/119937386201032211218977/

 

最开始接触projecteuler也就是几个月前看到laiyonghao大大在2008年发表的一篇博文《推荐几个好玩又有难度的编程网站》。projecteuler是其中第一个网站,也是我认为可玩性最高的一个网站。直到目前为止,中国大陆有1098个账号在上面活动,而用户人数最多的国家是美国,有11550个。这样的结果并不符合一个负责任大国所应有的表现,因此很有必要继续赶英超美(单英格兰在这天就有2267人)。

 
即使对于一个ACM弱鸟来说,projecteuler的模式也不会显得陌生,就是给出一问题,然后由你来进行求解。如果 正确,则你的排名就会上升,这样是一个相当有成就感的事情。当然,两者之间仍然是有一些不一样的。
 
  1. 首先,两者的提交内容不一样。ACM类型的网站需要你提交编写好的程序,上传好了代码之后在服务器端编译和进行judge,只有当你AC了之后,这个题目才算通过。而projecteuler则不一样,它只要求你提交答案。对于题目类型比较偏重数学的内容来说,projecteuler的设计自由度更大。
  2. 其次,限制程度不一样。ACM需要提交程序,自然对程序的运行时间和消耗的内存大小也有一定明确的限制,这就要求你对于某些蛮力无法搞笑解决的问题要学会变通,要求更高。而projecteuler允许你不局限于某种具体的编程语言,而是鼓励你用更多的方法来解决同一个问题。有人用C++,Java,python等等流行的程序语言语言。还有用php,perl,ruby,javascript等等流行的脚本语言来解题。更有出于装B或者是其他不可告人的目的而采用汇编来解题的:-)。总之答案是丰富多彩的,解决的途径自然也是丰富多彩的。
  3. 网站排名对人的影响不一样。玩ACM的时候,我总是想方设法的想刷高排名,所以在自己写不出代码的时候,也会想方法找到高手的代码,看懂然后提交来争取排名靠前。projecteuler则不一样,由于很多solution类型的网站(如 http://code.google.com/p/projecteuler-solutions/)的出现,你想刷的话,一天之内大概就能刷到第一名了,这样盲目刷分反而变得没意义了。因此我更喜欢把题目搞明白,代码运行清楚了,才把代码提交上去。
说到要把题目搞明白,除了自身的努力之外,不断的参考和学习很多不同的内容自然是少不了的。学习的途径自然有不少的。这个过程非常强调动手的能力,只有在动手的过程中,你才能学到更多深入的东西。例如,素数(primes)这样的概念,在中学甚至是小学的时候就有接触过。并且做projecteuler的题目的时候也会经常遇到跟素数相关的内容。能够把经常使用的某个范围的素数找出来,就显得很有必要了。

  要解决这个问题,首先就是要动手去搜索。我搜索到了 1000以内的素数表 ,很快自然也搜到了 10000以内的素数表 ,紧接着,我还能找到 列有 1000000以内的素数表 这样的乏味的blog内容。直到1后面出现了7个0,这才开始没有直接的答案可用。

  于是就被迫开始写代码了。我从最基本的暴力穷举的方法开始尝试,编写一个叫做素数生成器的C语言程序,直到感觉性能实在是太慢了的时候,就又开始找其他的方法了。云风在他的著作《我的编程感悟》讨论优化的问题时,也对上述问题进行了一个简单的讨论。其最终采用的方法,叫做埃拉托色尼筛子算法,是以欧几里德同时代的数学家埃拉托色尼命名的方法。这是可知的已经非常高效的方法,至于具体的实现,我会在以后的文章中探讨。

  除了上述搜索进而动手写代码的方法外,多参考别人的材料,学会站在巨人的肩上往往能达到事半功倍的效果。http://dcy.is-programmer.com/ 这个blog比较适合初学者,里面对前40题都有完整的python代码,适合那些希望写出精炼切高效代码的人。而 http://blog.skainet.net/ 是我发现的一个对每个题目都有比较详尽解释并且提供不同代码的blog,这里的题目比上一个更加深入一点,确实非常值得参考。
 
最后,学习自然也还是不能离开书本。《具体数学》(<concrete mathematics>)是我比较推崇的一本,里面有专门的一章讲述素数的各种有趣的特性。唯一不好的地方就是此书门槛较高,适合数学基础比较好而且英语也还不错的朋友,不过目前国内已经有中文的版本,大家上网搜搜就可以知道了。这样的书,最时候找一块特定的时间离开电脑,安心坐下来看看,你会对大师讲述的睿智和精妙赞叹不绝的。

C未解决的问题

1、定义一个数组,编程打印它的全排列。比如定义:

#define N 3
int a[N] = { 1, 2, 3 };
 
程序的主要思路是:
1. 把第1个数换到最前面来(本来就在最前面),准备打印1xx,再对后两个数2和3做全排列。
2. 把第2个数换到最前面来,准备打印2xx,再对后两个数1和3做全排列。
3. 把第3个数换到最前面来,准备打印3xx,再对后两个数1和2做全排列。
可见这是一个递归的过程,把对整个序列做全排列的问题归结为对它的子序列做全排列的问题,注
意我没有描述Base Case怎么处理,你需要自己想。你的程序要具有通用性,如果改变了N和数
组a的定义(比如改成4个数的数组),其它代码不需要修改就可以做4个数的全排列(共24种排
列)。
完成了上述要求之后再考虑第二个问题:如果再定义一个常量M表示从N个数中取几个数做排列(N
== M时表示全排列),原来的程序应该怎么改?
最后再考虑第三个问题:如果要求从N个数中取M个数做组合而不是做排列,就不能用原来的递归过
程了,想想组合的递归过程应该怎么描述,编程实现它。
 
 
 
要看的书
数据结构,操作系统,组成原理,网络

Python学习笔记(三)

有三种方法可以用来从集合中删除某个值。前两种,discard() 和 remove() 有细微的差异。 如果针对一个集合中不存在的值调用 discard() 方法,它不进行任何操作。不产生错误;只是一条空指令。 区别在这里:如果该值不在集合中,remove() 方法引发一个 KeyError 例外。

阅读全文

Python学习笔记(2)

学习笔记2

阅读全文

Python学习笔记(1)

转义符

假设你想要在一个字符串中包含一个单引号('),那么你该怎么指示这个字符串?例如,这个字符串是What's your name?。你肯定不会用'What's your name?'来指示它,因为Python会弄不明白这个字符串从何处开始,何处结束。所以,你需要指明单引号而不是字符串的结尾。可以通过 转义符 来完成这个任务。你用\'来指示单引号——注意这个反斜杠。现在你可以把字符串表示为'What\'s your name?'

阅读全文