强奸阿里巴巴一个笔试题

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)
每次一个人可以把一个棋子往左移若干步,
但是不能跨越其它棋子,也要保证每个格子至多只有一个棋子.
两个人轮流移动,移动不了的为输,问先手是不是有必胜策略.
...全文
18372 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)
内容概要:本文介绍了WiFiSupply斯普莱WFS7000XA工业级大功率双频无线AP基站,该设备支持2.4G/5GHz双频段,最大带宽达433Mbps,具备高发射功率(26dBm)、高接收灵敏度(-97dBm)和超远传输距离(可达1.5公里以上)。产品采用工业级设计,支持TDMA时分多址、私有协议、Fast Roaming快速漫游(切换延迟≤30ms)、抗干扰能力强,通信延迟低于1ms,支持主流PLC通信协议。设备支持胖瘦一体模式、多种供电方式(含POE)、IP54防护等级、-45~85℃宽温工作,适用于复杂电磁与恶劣环境。具备多重安全机制,如巨量安全隧道、VLAN、QoS、防火墙、MAC/IP过滤等,并支持SNMP、SSH、API对接及云平台集中管理,满足工业4.0、智慧物流、AGV/AMR小车、无人机遥控、车载视频传输等场景的无线组网需求。; 适合人群:从事工业自动化、物联网、智能制造、智慧物流等领域,具备一定网络与通信基础知识的技术人员及系统集成商。; 使用场景及目标:①用于AMR/AGV/RGV小车、穿梭车、天车等移动设备的无线联网与稳定通信;②实现室内外远距离无线桥接与覆盖,支持高速移动下的无缝漫游与低延迟数据传输;③构建高安全、高可靠的工业无线网络,支持PLC协议传输与远程集中管控。; 阅读建议:此文档侧重产品技术参数与工业应用场景,建议结合实际部署需求重点关注其抗干扰能力、漫游性能、供电方式与管理接口,便于在复杂工业环境中选型与集成。
内容概要:本文围绕基于序贯蒙特卡洛模拟法的配电网可靠性评估展开系统性研究,深入阐述了该方法在电力系统可靠性分析中的理论基础与技术优势。相较于非序贯方法,序贯蒙特卡洛通过引入时间序列模拟,能够精确刻画系统状态的时序演变过程与元件故障的动态特性,有效提升对复杂运行场景的模拟能力。研究建立了配电网中关键设备的故障模型与状态转移机制,采用时序仿真方法对系统运行状态进行抽样,并在此基础上统计计算系统平均停电频率(SAIFI)、系统平均停电持续时间(SAIDI)等核心可靠性指标。为验证方法的有效性与实用性,研究以标准IEEE测试系统为案例进行仿真分析,充分展示了该方法在处理多重故障、网络重构及复杂拓扑结构下的优越性能,并配套提供了完整的Matlab代码实现,增强了研究成果的可复现性与工程应用价值。; 适合人群:具备电力系统分析、概率统计基础知识以及一定Matlab编程能力的高校研究生、从事电力系统规划、运行与可靠性评估的科研人员及工程技术人员。; 使用场景及目标:①用于高等院校相关课程的教学演示与学生实践,深化对可靠性评估理论的理解;②为配电网规划、运维策略制定及升级改造提供科学、量化的决策支持工具;③支撑高水平学术论文的成果复现、方法改进与算法创新研究。; 阅读建议:此资源集理论推导、算法实现与仿真验证于一体,建议读者在掌握蒙特卡洛模拟基本原理的基础上,结合文档内容仔细研读并调试所提供的Matlab代码,通过调整系统参数、故障率等输入条件,观察其对SAIFI、SAIDI等输出指标的影响,从而深入理解状态抽样、时序模拟与可靠性指标统计等关键技术环节的实现细节与内在逻辑。

65,214

社区成员

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

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