强奸阿里巴巴一个笔试题

baihacker 2009-10-17 01:11:55
加精
作者:baihacker
来源:http://hi.baidu.com/feixue http://hi.csdn.net/baihacker

问题描述:
12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
这个笔试题,很YD,因为把某个递归关系隐藏得很深.

问题分析:
我们先把这12个人从低到高排列,然后,选择6个人排在第一排,那么剩下的6个肯定是在第二排.
用0表示对应的人在第一排,用1表示对应的人在第二排,那么含有6个0,6个1的序列,就对应一种方案.
比如000000111111就对应着
第一排:0 1 2 3 4 5
第二排:6 7 8 9 10 11
010101010101就对应着
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
问题转换为,这样的满足条件的01序列有多少个.
观察1的出现,我们考虑这一个出现能不能放在第二排,显然,在这个1之前出现的那些0,1对应的人
要么是在这个1左边,要么是在这个1前面.而肯定要有一个0的,在这个1前面,统计在这个1之前的0和1的个数.
也就是要求,0的个数大于1的个数.
OK,问题已经解决.
如果把0看成入栈操作,1看成出栈操作,就是说给定6个元素,合法的入栈出栈序列有多少个.
这就是catalan数,这里只是用于栈,等价地描述还有,二叉树的枚举,多边形分成三角形的个数,圆括弧插入公式中的
方法数,其通项是c(2n, n)/(n+1).

在<<计算机程序设计艺术>>,第三版,Donald E.Knuth著,苏运霖译,第一卷,508页,给出了证明:
问题大意是用S表示入栈,X表示出栈,那么合法的序列有多少个(S的个数为n)
显然有c(2n, n)个含S,X各n个的序列,剩下的是计算不允许的序列数(它包含正确个数的S和X,但是违背其它条件).
在任何不允许的序列中,定出使得X的个数超过S的个数的第一个X的位置.然后在导致并包括这个X的部分序列中,以
S代替所有的X并以X代表所有的S.结果是一个有(n+1)个S和(n-1)个X的序列.反过来,对一垢一种类型的每个序列,我们都能
逆转这个过程,而且找出导致它的前一种类型的不允许序列.例如XXSXSSSXXSSS必然来自SSXSXXXXXSSS.这个对应说明,不允许
的序列的个数是c(2n, n-1),因此an = c(2n, n) - c(2n, n-1).[Comptes Rendus Acad.Sci.105(Paris, 1887), 436~437]

验证:
其中F表示前排,B表示后排,在枚举出前排的人之后,对应的就是后排的人了,然后再验证是不是满足后面的比前面对应的人高的要求.
#include <iostream>
using namespace std;

int bit_cnt(int n)
{
int result = 0;
for (; n; n &= n-1, ++result);
return result;
}

int main()
{
int F[6], B[6];
int ans = 0;
for (int state = 0; state < (1 << 12); ++state) if (bit_cnt(state) == 6)
{
int i = 0, j = 0;
for (int k = 0; k < 12; ++k) if (state&(1<<k)) F[i++] = k; else B[j++] = k;
int ok = 1;
for (int k = 0; k < 6; ++k) if (B[k] < F[k]) {ok = 0; break;}
ans += ok;
}
cout << ans << endl;
return 0;
}
结果:132
而c(12, 6)/7 = 12*11*10*9*8*7/(7*6*5*4*3*2) = 132
注意:c(2n, n)/(n+1) = c(2n, n) - c(2n, n-1)

估计出题的人也读过<<计算机程序艺术>>吧.

PS:
另一个很YD的问题:
有编号为1到n(n可以很大,不妨在这里假定可以达到10亿)的若干个格子,从左到右排列.
在某些格子中有一个棋子,不妨设第xi格有棋子(1<=i<=k, 1<=k<=n)
每次一个人可以把一个棋子往左移若干步,
但是不能跨越其它棋子,也要保证每个格子至多只有一个棋子.
两个人轮流移动,移动不了的为输,问先手是不是有必胜策略.
...全文
17810 546 打赏 收藏 转发到动态 举报
写回复
用AI写文章
546 条回复
切换为时间正序
请发表友善的回复…
发表回复
ligangdili 2012-06-07
  • 打赏
  • 举报
回复
每次取出两个,保证高的左矮的右即可吧(因为最终分组之后的,排列方式是固定的)
jerryjerryone 2012-06-07
  • 打赏
  • 举报
回复
我的代码:首先要把Arr排好序,然后用递归。(上面的排版不好,再发一遍)
void PrintArr( int * arr, int size )
{
for( int i = 0; i < size; i++ )
{
cout << arr[i] << " ";
}
cout << endl;
}

void SortP( int *arr, int size, int cursize, int *fst, int fstsize, int *sec, int secsize )
{
if( cursize == 0 )
{
if( ( fstsize == size/2 ) && ( secsize == size/2 ) )
{
PrintArr( fst, fstsize );
PrintArr( sec, secsize );
cout << endl;
return;
}
}

if( ( fstsize > size/2 ) || ( secsize > size/2 ) || ( cursize < 0 ))
{
return;
}
if( fstsize > secsize )
{
* (fst + fstsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize + 1, sec, secsize );
if( *arr < *( fst + secsize) )
{
*( sec + secsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize, sec, secsize + 1 );
}
}
else if( fstsize < secsize )
{
*( sec + secsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize, sec, secsize + 1 );
if( *arr > *( sec + fstsize ) )
{
*( fst + fstsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize + 1, sec, secsize );
}
}
else
{
* (fst + fstsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize + 1, sec, secsize );

*( sec + secsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize, sec, secsize + 1 );
}
}

int main()
{
int A[] = { 2,3,5,7,9,11,14, 23,24,27 };
int B[6];
int C[6];

SortP( A, 10, 10, B, 0, C, 0 );
return 0;
}
jerryjerryone 2012-06-07
  • 打赏
  • 举报
回复
我的代码:首先要把Arr排好序,然后用递归。
void PrintArr( int * arr, int size )
{
for( int i = 0; i < size; i++ )
{
cout << arr[i] << " ";
}
cout << endl;
}

void SortP( int *arr, int size, int cursize, int *fst, int fstsize, int *sec, int secsize )
{
if( cursize == 0 )
{
if( ( fstsize == size/2 ) && ( secsize == size/2 ) )
{
PrintArr( fst, fstsize );
PrintArr( sec, secsize );
cout << endl;
return;
}
}

if( ( fstsize > size/2 ) || ( secsize > size/2 ) || ( cursize < 0 ))
{
return;
}
if( fstsize > secsize )
{
* (fst + fstsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize + 1, sec, secsize );
if( *arr < *( fst + secsize) )
{
*( sec + secsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize, sec, secsize + 1 );
}
}
else if( fstsize < secsize )
{
*( sec + secsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize, sec, secsize + 1 );
if( *arr > *( sec + fstsize ) )
{
*( fst + fstsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize + 1, sec, secsize );
}
}
else
{
* (fst + fstsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize + 1, sec, secsize );

*( sec + secsize ) = *arr;
SortP( arr + 1, size, cursize - 1, fst, fstsize, sec, secsize + 1 );
}
}

int main()
{
int A[] = { 2,3,5,7,9,11,14, 23,24,27 };
int B[6];
int C[6];

SortP( A, 10, 10, B, 0, C, 0 );
return 0;
}
wanglufei 2011-07-13
  • 打赏
  • 举报
回复
二叉查找树?
iphonec 2010-11-11
  • 打赏
  • 举报
回复
10395
ricky5201 2010-09-10
  • 打赏
  • 举报
回复
有点意思~~~
  • 打赏
  • 举报
回复
都是一群大牛啊
djjlove_2008 2010-07-10
  • 打赏
  • 举报
回复
阿里巴巴的董事局主席,马云也真是IT界的怪才,呵呵。
djjlove_2008 2010-07-10
  • 打赏
  • 举报
回复
/*另一个很YD的问题:
有编号为1到n(n可以很大,不妨在这里假定可以达到10亿)的若干个格子,从左到右排列.
在某些格子中有一个棋子,不妨设第xi格有棋子(1<=i<=k, 1<=k<=n)
每次一个人可以把一个棋子往左移若干步,
但是不能跨越其它棋子,也要保证每个格子至多只有一个棋子.
两个人轮流移动,移动不了的为输,问先手是不是有必胜策略.*/

当然,我在微软的《编程之美》中也看到类似的问题,对于你的第一问题,你的证明也看过,推出的结果为catalan数,很经典的一个数,呵呵。今天看过飞雪哥的帖子,受益非浅也,看来名企很喜欢用这类问题来面试呀,第二个问题,可以转换为典型的NIM游戏,可以采用数学归纳法来得出一般性的结论。
I:很明显,当棋盘上只有一个棋子时,先手方法可以轻而易举地取胜,因为只要移到一次就行了。
II:当棋盘上有两颗棋子时,先手方如果移动左边的一颗棋子,后手方可以怎么样都可以跟着这颗棋子,最后先手方会作茧自缚,最终移动棋子,而输掉,但换个方式,先手方可以先移动最右边的棋子,这样就可以转化为刚才的问题,先手方必胜。
III:当棋盘上有三颗棋子,相对起来就比较复杂,我们把它数学化一下:选择棋子的移动肯定只有3种方式,分别从最左边到最右方的棋子,如何选择才能致胜了,很明显可以移动若干格,就不用考虑每次只移动一格了,反正对方可以跟着你,你一下移动到最左边也是一样的,如果移动最左边的棋子到最左方,后手方可以移动最右边的棋子,先手会输,如果先手方移动最右方的棋子,后手方也可以获胜,但如果先手方移动中间的一颗棋子,后手方无论如何,都必败。
从上,我们不可能再分析4颗,5颗了,毕竟太复杂,且以上都假设棋子不相邻,因为如果相邻的话,转换后也可以变为上述情况,这时我们想到了,刚上C语言课程的的异或操作,我们假设空的棋盘上的数值为0,棋子的值为1,先手方要想获胜,必须想办法把棋盘上的所有的(包括棋子和棋格)异或和的值变为0,这时写程序应该不难吧,就算是10亿个数,所有的数异或的速度也很快,而且也只要一个临时变量的空间。妙哉妙哉,我也得益于微软的《编程之美》,希望飞雪哥赐教。
dcw0402 2010-06-27
  • 打赏
  • 举报
回复
MARK
hellobene 2010-06-26
  • 打赏
  • 举报
回复
弱弱地问:
题目好像没要求6个人一排吧
0
1 2 3 4 5 6 7 8 9 10 11
这样不行吗?
pi88dian88 2010-06-25
  • 打赏
  • 举报
回复
另一个很YD的问题:
有编号为1到n(n可以很大,不妨在这里假定可以达到10亿)的若干个格子,从左到右排列.
在某些格子中有一个棋子,不妨设第xi格有棋子(1<=i<=k, 1<=k<=n)
每次一个人可以把一个棋子往左移若干步,
但是不能跨越其它棋子,也要保证每个格子至多只有一个棋子.
两个人轮流移动,移动不了的为输,问先手是不是有必胜策略.


不知道对不对
可以扫描一次格子,第一个棋子的sg值为开始到第一个棋子出现的格子的距离减1,从第二个棋子开始的sg[i]=sg[i-1] + distance(第i个棋子的位置-第(i-1)个棋子的位置)
然后对各个sg值取异或,看结果
momos 2010-06-19
  • 打赏
  • 举报
回复
mark
learn_day_up 2010-06-15
  • 打赏
  • 举报
回复
research一下
shihunjiangjie 2010-06-04
  • 打赏
  • 举报
回复
不错的一个题啊
勇敢的搬砖人 2010-05-26
  • 打赏
  • 举报
回复
lishuaibest 2010-05-15
  • 打赏
  • 举报
回复
的负担
探花 2010-04-28
  • 打赏
  • 举报
回复
菜鸟报到
boringcpu 2010-04-25
  • 打赏
  • 举报
回复
我记得高考前好像看到过……感觉像排列组合……
keristef 2010-02-26
  • 打赏
  • 举报
回复

【招聘】月薪10K起招聘C++开发工程师

http://topic.csdn.net/u/20100225/17/d973b9b7-1a5b-4a31-99f9-5347a973aa81.html?seed=157601369&r=63586978#r_63586978

将http后面的标点符号换作英文的即可
加载更多回复(526)
阿里巴巴校园招聘笔试面试题淘宝校园招聘笔试试题27个文档资料合集: 2012阿里巴巴校园招聘阿里云C++笔试试题.doc 2013年阿里巴巴校园招聘笔试试题研发工程师.doc 2014年3月阿里巴巴实习招聘笔试题及部分答案.docx 2014年阿里巴巴校园招聘笔试题杭州站-研发类.doc 淘宝2011实习招聘笔试.doc 淘宝校园招聘清华笔试试题.doc 淘宝校园招聘笔试试题.doc 淘宝笔试题及部分答案.docx 阿里巴巴2010校园招聘技术类笔试试题(Java,搜索研发,C++,测试工程师)南京站.docx 阿里巴巴2014校园招聘笔试试题-系统工程师-北京站.doc 阿里巴巴2014校园招聘笔试试题-软件研发工程+网友版答案.docx 阿里巴巴2014校园招聘笔试试题-软件研发工程师+答案.doc 阿里巴巴2014校园招聘笔试题-研发工程师-全国卷.doc 阿里巴巴2014校园招聘笔试题及参考答案-研发工程师-哈尔滨站.doc 阿里巴巴2014校园招聘笔试题目-数据分析师职位(回忆版).pdf 阿里巴巴2014秋季校园招聘-软件研发工程师笔试题-文字版.doc 阿里巴巴2014秋季校园招聘笔试题-测试开发工程师北京卷.pdf 阿里巴巴_java_研发成功笔面试总结.doc 阿里巴巴年校园招聘笔试题(b2b-技术部-工程师)java,算法,C++,测试.doc 阿里巴巴校园招聘Oracle_DBA笔试题及参考答案.doc 阿里巴巴校园招聘前端在线笔试.doc 阿里巴巴校园招聘测试笔试题总结.doc 阿里巴巴校园招聘销售类笔试题.doc 阿里巴巴校园招聘阿里云笔试试题题目.doc 阿里巴巴校园招聘面试试题合集总结.docx 阿里巴巴集团2014校园招聘系统工程师北京站笔试题.doc

64,647

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧