2012年九度互动社区淘宝实习生春季招聘上机考试 http://ac.jobdu.com/contest.php?cid=1035
虽然过期,练练也未尝不是件好事。
时间限制:1 秒 内存限制:32 兆 特殊判题:否
淘宝公司内部有许多新鲜的小玩具,例如淘宝智能机器人。小时候,大家都玩过那个吃豆子的游戏吧,这机器人就是按照这个游戏设计的,它会朝着豆子的方向行走。不过机器人还存在一个bug,他只会朝南和朝东走。现在有一块空地,分成了n*m个格子,每个格子内有一颗豆子。机器人的起点在西北角,终点在东南角。请问机器人从起点到终点有多少种不同的方法。
每个案例输入只有一行,有n和m两个正整数,n,m均小于等于10^3。由于答案很大,所以答案对10009取余。
对于每个案例,输出一行,输出机器人从起点到终点的总方法数。
2 2 3 3
2 6
题目咋一看不难。就是使用一个递归,当前点到终点的方法数无非就是向南的方法数与向东走的方法数之和。递归下去,当到达边界时,不管向哪个方向走方法只有一种了,这也就是递归的终止条件。马上得出:
1 int func5(int n, int m) 2 { 3 if (n==1 || m==1) 4 { 5 return 1; 6 } 7 else 8 { 9 return func5(n-1,m)+ func5(n, m-1); 10 } 11 }
可是问题来了,时间要限制在一秒钟。当n、m大的时候递归就非常慢了。而且这里没有考虑溢出问题,题目中已经给出应该模10009,即改最后一句:
return func5(n-1,m)%10009+ func5(n, m-1)%10009;
所以要使用非递归算法:
分析,如果使用一张n*m的二维数组保存,每一个点到终点的位置,逆着求回去将可以得到结果。细节就不写了。。。
但其实大部分结果只是一个中间结果,后来就不再需要,故可以压缩。压缩成一维数组,一维数组就只使用min(n,m)的大小(根据对称性可证)。最后有一下代码:
1 int func6(int a, int b) 2 { 3 unsigned long *p,tmp; 4 int i,j,n,m; 5 6 if (a>b) 7 { 8 n = a; 9 m = b; 10 } 11 else 12 { 13 m=a; 14 n=b; 15 } 16 17 p = (unsigned long *)malloc(sizeof(int)*m); 18 19 for (int k=0; k<m; k++) 20 { 21 p[k]=1; 22 } 23 24 for (i=1; i<n; i++) 25 { 26 for (j=1; j<m; j++) 27 { 28 p[j] = (p[j-1]+p[j])%10009; 29 } 30 } 31 tmp = p[m-1]; 32 free(p); 33 return tmp; 34 }
毕。
为了找个工作不容易啊,还在挣扎中~ ~~o(>_<)o ~~
修:今做了题目,类似的,求要求不过某一点的路线选择方法。结果蒙了,手算啊!折腾良久,未果,逐网查。
结果化成了一道数学排列组合题目。由于不管向东或向南总数都要走n+m步。你可以从总步数中选出n向南走(剩余的向东了),这样就可以得出C(n+m,n)既是结果了。(也可以为C(n+m,m),相当于你从总步数中选出m向东走,剩余的向南走)这样才可以快速的手算出结果。