76.复杂链表的复制
题目:有一个复杂链表,其结点除了有一个m_pNext指针指向下一个结点外,
还有一个m_pSibling指向链表中的任一结点或者NULL。其结点的C++定义如下:
struct ComplexNode
{
int m_nValue;
ComplexNode* m_pNext;
ComplexNode* m_pSibling;
};
首先是原始的链表
然后我们还是首先复制每一个结点N为N*,不同的是我们将N*让在对应的N后面,即为
然后我们要确定每一个N*的sibling分量,非常明显,N的sibling分量的next就是N*的sibling分量。
最后,将整个链表拆分成原始链表和拷贝出的链表。
这样,我们就解决了一个看似非常混乱和复杂的问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
struct
Node
{
int
val;
Node* next;
Node* sibling;
};
void
Clone(Node* head)
{
Node* current=head;
while
(current)
{
Node* temp=
new
Node;
temp->val=current->val;
temp->next=current->next;
temp->sibling=NULL;
current->next=temp;
current=temp->next;
}
}
void
ConstructSibling(Node* head)
{
Node* origin=head;
Node* clone;
while
(origin)
{
clone=origin->next;
if
(origin->sibling)
clone->sibling=origin->sibling->next;
origin=clone->next;
}
}
Node* Split(Node* head)
{
Node *CloneHead,*clone,*origin;
origin=head;
if
(origin)
{
CloneHead=origin->next;
origin->next=CloneHead->next;
origin=CloneHead->next;
clone=CloneHead;
}
while
(origin)
{
Node* temp=origin->next;
origin->next=temp->next;
origin=origin->next;
clone->next=temp;
clone=temp;
}
return
CloneHead;
}
//the whole thing
Clone(head);
ConstructSibling(head);
return
Split(head);
|
77.关于链表问题的面试题目如下:
1.给定单链表,检测是否有环。
使用两个指针p1,p2从链表头开始遍历,p1每次前进一步,p2每次前进两步。如果p2到达链表尾部,
说明无环,否则p1、p2必然会在某个时刻相遇(p1==p2),从而检测到链表中有环。
2.给定两个单链表(head1, head2),检测两个链表是否有交点,如果有返回第一个交点。
如果head1==head2,那么显然相交,直接返回head1。
否则,分别从head1,head2开始遍历两个链表获得其长度len1与len2,假设len1>=len2,
那么指针p1由head1开始向后移动len1-len2步,指针p2=head2,
下面p1、p2每次向后前进一步并比较p1p2是否相等,如果相等即返回该结点,
否则说明两个链表没有交点。
4.只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点。
办法很简单,首先是放p中数据,然后将p->next的数据copy入p中,接下来删除p->next即可。
5.只给定单链表中某个结点p(非空结点),在p前面插入一个结点。
办法与前者类似,首先分配一个结点q,将q插入在p后,接下来将p中的数据copy入q中,
然后再将要插入的数据记录在p中。
78.链表和数组的区别在哪里?
分析:主要在基本概念上的理解。
但是最好能考虑的全面一点,现在公司招人的竞争可能就在细节上产生,
谁比较仔细,谁获胜的机会就大。
79.
1.编写实现链表排序的一种算法。说明为什么你会选择用这样的方法?
2.编写实现数组排序的一种算法。说明为什么你会选择用这样的方法?
3.请编写能直接实现strstr()函数功能的代码。
80.阿里巴巴一道笔试题
今天阿里淘宝笔试中碰到两道组合数学题,感觉非常亲切,但是笔试中失踪推导不出来
后来查了下,原来是Catalan数。悲剧啊,现在整理一下
Catalan数——卡特兰数】
一.Catalan数的定义令h(1)=1,Catalan数满足递归式:h(n) = h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1),n>=2该递推关系的解为:h(n) = C(2n-2,n-1)/n,n=1,2,3,...(其中C(2n-2,n-1)表示2n-2个中取n-1个的组合数)
问题描述:
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
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<
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)
每次一个人可以把一个棋子往左移若干步,
但是不能跨越其它棋子,也要保证每个格子至多只有一个棋子.
两个人轮流移动,移动不了的为输,问先手是不是有必胜策略.
三.Catalan数的典型应用:
1.括号化问题。矩阵链乘: P=A1×A2×A3×……×An,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?
2.将多边行划分为三角形问题。将一个凸多边形区域分成三角形区域(划分线不交叉)的方法数?
类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
3.出栈次序问题。一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?
类似:有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)
类似:一位大城市的律师在他住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果他从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
分析:对于每一个数来说,必须进栈一次、出栈一次。我们把进栈设为状态‘1’,出栈设为状态‘0’。n个数的所有状态对应n个1和n个0组成的2n位二进制数。由于等待入栈的操作数按照1‥n的顺序排列、入栈的操作数b大于等于出栈的操作数a(a≤b),因此输出序列的总数目=由左而右扫描由n个1和n个0组成的2n位二进制数,1的累计数不小于0的累计数的方案种数。
在2n位二进制数中填入n个1的方案数为c(2n,n),不填1的其余n位自动填0。从中减去不符合要求(由左而右扫描,0的累计数大于1的累计数)的方案数即为所求。
不符合要求的数的特征是由左而右扫描时,必然在某一奇数位2m+1位上首先出现m+1个0的累计数和m个1的累计数,此后的2(n-m)-1位上有n-m个 1和n-m-1个0。如若把后面这2(n-m)-1位上的0和1互换,使之成为n-m个0和n-m-1个1,结果得1个由n+1个0和n-1个1组成的2n位数,即一个不合要求的数对应于一个由n+1个0和n-1个1组成的排列。
反过来,任何一个由n+1个0和n-1个1组成的2n位二进制数,由于0的个数多2个,2n为偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在后面部分0和1互换,使之成为由n个0和n个1组成的2n位数,即n+1个0和n-1个1组成的2n位数必对应一个不符合要求的数。
因而不合要求的2n位数与n+1个0,n-1个1组成的排列一一对应。
显然,不符合要求的方案数为c(2n,n+1)。由此得出 输出序列的总数目=c(2n,n)-c(2n,n+1)=1/(n+1)*c(2n,n)。
(这个公式的下标是从h(0)=1开始的)
先来几组百度的面试题:
===================
分析:最原始的方法是检查每一个数 array[i] ,看是否左边的数都小于等于它,右边的数都大于等于它。这样做的话,要找出所有这样的数,时间复杂度为O(N^2)。
其实可以有更简单的方法,我们使用额外数组,比如rightMin[],来帮我们记录原始数组array[i]右边(包括自己)的最小值。假如原始数组为: array[] = {7, 10, 2, 6, 19, 22, 32}, 那么rightMin[] = {2, 2, 2, 6, 19, 22, 32}. 也就是说,7右边的最小值为2, 2右边的最小值也是2。
有了这样一个额外数组,当我们从头开始遍历原始数组时,我们保存一个当前最大值 max, 如果当前最大值刚好等于rightMin[i], 那么这个最大值一定满足条件。还是刚才的例子。
第一个值是7,最大值也是7,因为7 不等于 2, 继续,
第二个值是10,最大值变成了10,但是10也不等于2,继续,
第三个值是2,最大值是10,但是10也不等于2,继续,
第四个值是6,最大值是10,但是10不等于6,继续,
第五个值是19,最大值变成了19,而且19也等于当前rightMin[4] = 19, 所以,满足条件。
#include2 3 using namespace std; 4 5 #define max(a,b) a>b?a:b 6 #define min(a,b) a 7 8 void findNum(int data[],int len) 9 { 10 int* a = new int[len]; 11 int* b = new int[len]; 12 a[len-1] = data[len-1]; 13 for (int i = len-2;i > 0;i--) 14 { 15 a[i] = min(data[i],a[i+1]); 16 } 17 18 if (data[0] <= a[1]) 19 { 20 cout<<"0:"<0]<<endl; 21 } 22 23 a[0] = data[0]; 24 if (data[1] >= a[0] && data[1] <= a[2]) 25 { 26 cout<<"1:"<1]<<endl; 27 } 28 29 for (int i = 1;i < len-2;i++) 30 { 31 a[i] = max(data[i],a[i-1]); 32 if (data[i+1] >= a[i] && data[i+1] <= a[i+2]) 33 { 34 cout<1<<":"<1]<<endl; 35 } 36 } 37 a[len-2] = max(data[len-2],a[len-3]); 38 if (data[len-1] >= a[len-2]) 39 { 40 cout< 1<<":"<1]<<endl; 41 } 42 } 43 44 int main() 45 { 46 int data[10] = {1,3,2,4,6,7,5,9,11,10}; 47 findNum(data,10); 48 }
文件的大小上限是10G,不可能在内存操作了。考虑设计一种hash使得如果两个字符串维相反串能得出相同的hash值,然后用该hash将文件中的字符串散列到不同的文件中,再在各文件中进行匹配。比如这样的hash函数对字符串上所有字符的ascii求和,因为长度在1K以内,因此范围在int之内。更进一步,可以在上面那个hash后面再加一个字符串长度,可以得到更好的散列效果。
在各个单独文件中匹配时,如果采用的是第二种hash函数,那么该文件中的所有字符串都有相同的长度。如果hash效果好,那么这个文件应该小到可以在内存中进行操作了。将文件拷贝为两份,分别按照不同规则hash:第一份按前k位哈希,第二份将字符串的头尾进行颠倒后按前k位哈希(只是对于排序算法颠倒,不必实际颠倒)。这里的按前k位哈希只需要前k位相同能得到相同结果就好,比如第i位的ascii乘以2^i。两份拷贝中hash值相同的就很可能是要求的相反串对了,再进行实际匹配,工作量应该就可以接受了。
3.STL的set用什么实现的?为什么不用hash?
82.第2组百度面试题
1.给出两个集合A和B,其中集合A={name},
集合B={age、sex、scholarship、address、...},
要求:
问题1、根据集合A中的name查询出集合B中对应的属性信息;
问题2、根据集合B中的属性信息(单个属性,如age<20等),查询出集合A中对应的name。
2.给出一个文件,里面包含两个字段{url、size},
即url为网址,size为对应网址访问的次数,
要求:
问题1、利用Linux Shell命令或自己设计算法,
查询出url字符串中包含“baidu”子字符串对应的size字段值;
问题2、根据问题1的查询结果,对其按照size由大到小的排列。
(说明:url数据量很大,100亿级以上)
83.第3组百度面试题
1.今年百度的一道题目
百度笔试:给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。
要求:空间复杂度O(1),时间复杂度为O(n)。
2.百度笔试题
用C语言实现函数void * memmove(void *dest, const void *src, size_t n)。
memmove函数的功能是拷贝src所指的内存内容前n个字节到dest所指的地址上。
分析:
由于可以把任何类型的指针赋给void类型的指针
这个函数主要是实现各种数据类型的拷贝。
原型:extern void *memmove(void *dest, const void *src, unsigned int count);
功能:由src所指内存区域复制count个字节到dest所指内存区域。
说明:src和dest所指内存区域可以重叠,但复制后src内容会被更改。函数返回指向dest的指针。
功能类似于memcpy,不同的是memcpy内存区域不可重叠
例子:
char *p="hello world!";
char *q=(char*)malloc(sizeof(char)*strlen(p));
memmove(q,p,sizeof(p)+1);
1.memmove
函数原型:void *memmove(void *dest, const void *source, size_t count)
返回值说明:返回指向dest的void *指针
参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数
函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。
memmove(),如果两函数重叠,赋值仍正确进行。
如果你不能保证是否有重叠,为了确保复制的正确性,你必须用memmove
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if((dest + count
85.又见字符串的问题
1.给出一个函数来复制两个字符串A和B。
字符串A的后几个字节和字符串B的前几个字节重叠。
分析:记住,这种题目往往就是考你对边界的考虑情况。
2.已知一个字符串,比如asderwsde,寻找其中的一个子字符串比如sde的个数,
如果没有返回0,有的话返回子字符串的个数。
using namespace std; struct TreeNode { int m_nValue; TreeNode *m_pLeft; TreeNode *m_pRight; }; //把一个有序整数数组放到二叉树
void RecurCreateTree(int *p, int length, TreeNode *&pHead) { if (length > 0) { pHead = new TreeNode; int mid = length/2; pHead->m_nValue = p[mid]; pHead->m_pLeft = NULL; pHead->m_pRight = NULL; RecurCreateTree(p, mid, pHead->m_pLeft); RecurCreateTree(p + mid + 1, length - mid - 1, pHead->m_pRight);; } else { pHead = NULL; } } //中序递归遍历
void MidRecurTraversal(TreeNode* pHead) { if (NULL != pHead) { MidRecurTraversal(pHead->m_pLeft); cout<m_nValue<<" "; MidRecurTraversal(pHead->m_pRight); } } int _tmain(int argc, _TCHAR* argv[]) { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12}; TreeNode *pHead = NULL; RecurCreateTree(arr, sizeof(arr)/sizeof(arr[0]), pHead); MidRecurTraversal(pHead); cout< return 0; }
而,学会把递归改称非递归也是一种必要的技术。
毕竟,递归会造成栈溢出,关于系统底层的程序中不到非不得以最好不要用。
但是对某些数学问题,就一定要学会用递归去解决。
87.
1.大整数数相乘的问题。(这是2002年在一考研班上遇到的算法题)
2.求最大连续递增数字串(如“ads3sl456789DF3456ld345AA”中的“456789”)
3.实现strstr功能,即在父串中寻找子串首次出现的位置。
(笔试中常让面试者实现标准库中的一些函数)
88.2005年11月金山笔试题。编码完成下面的处理函数。
函数将字符串中的字符'*'移到串的前部分,
前面的非'*'字符后移,但不能改变非'*'字符的先后顺序,函数返回串中字符'*'的数量。
如原始串为:ab**cd**e*12,
处理后为*****abcde12,函数并返回值为5。(要求使用尽量少的时间和辅助空间)
89.神州数码、华为、东软笔试题
1.2005年11月15日华为软件研发笔试题。实现一单链表的逆转。
2.编码实现字符串转整型的函数(实现函数atoi的功能),据说是神州数码笔试题。如将字符
串 ”+123”123, ”-0123”-123, “123CS45”123, “123.45CS”123, “CS123.45”0
3.快速排序(东软喜欢考类似的算法填空题,又如堆排序的算法等)
4.删除字符串中的数字并压缩字符串。
如字符串”abc123de4fg56”处理后变为”abcdefg”。注意空间和效率。
(下面的算法只需要一次遍历,不需要开辟新空间,时间复杂度为O(N))
5.求两个串中的第一个最长子串(神州数码以前试题)。
如"abractyeyt","dgdsaeactyey"的最大子串为"actyet"。
90.
1.不开辟用于交换数据的临时空间,如何完成字符串的逆序
(在技术一轮面试中,有些面试官会这样问)。
2.删除串中指定的字符
(做此题时,千万不要开辟新空间,否则面试官可能认为你不适合做嵌入式开发)
3.判断单链表中是否存在环。
91.
1.一道著名的毒酒问题
有1000桶酒,其中1桶有毒。而一旦吃了,毒性会在1周后发作。
现在我们用小老鼠做实验,要在1周内找出那桶毒酒,问最少需要多少老鼠。
2.有趣的石头问题
有一堆1万个石头和1万个木头,对于每个石头都有1个木头和它重量一样,
把配对的石头和木头找出来。
92.
1.多人排成一个队列,我们认为从低到高是正确的序列,但是总有部分人不遵守秩序。
如果说,前面的人比后面的人高(两人身高一样认为是合适的),
那么我们就认为这两个人是一对“捣乱分子”,比如说,现在存在一个序列:
176, 178, 180, 170, 171
这些捣乱分子对为
<176, 170>, <176, 171>, <178, 170>, <178, 171>, <180, 170>, <180, 171>,
那么,现在给出一个整型序列,请找出这些捣乱分子对的个数(仅给出捣乱分子对的数目即可,不用具体的对)
要求:
输入:
为一个文件(in),文件的每一行为一个序列。序列全为数字,数字间用”,”分隔。
输出:
为一个文件(out),每行为一个数字,表示捣乱分子的对数。
详细说明自己的解题思路,说明自己实现的一些关键点。
并给出实现的代码 ,并分析时间复杂度。
限制:
输入每行的最大数字个数为100000个,数字最长为6位。程序无内存使用限制。
93.在一个int数组里查找这样的数,它大于等于左侧所有数,小于等于右侧所有数。
直观想法是用两个数组a、b。a[i]、b[i]分别保存从前到i的最大的数和从后到i的最小的数,
一个解答:这需要两次遍历,然后再遍历一次原数组,
将所有data[i]>=a[i-1]&&data[i]<=b[i]的data[i]找出即可。
给出这个解答后,面试官有要求只能用一个辅助数组,且要求少遍历一次。
动态规划求解。设f[i][j]为以a[i],a[j]结尾的等差数列的最长长度。那么
递归方程为:f[i][j]=max{f[k][i]+1,a[k]-a[i]==a[i]-a[j]},起始条件f[i][j]=1;伪代码如下:
for(int k =0; k for(int i=k+1;i for(int j=i+1;j if(a[k]-a[i] == a[i]-a[j]) f[i][j] = (f[i][j] 而,最长长度为即为max{f[i][j]},即以a[i],a[j]结尾,通过一次查找即可求出是那些元素组成的解。复杂度O(n^3)。
95.华为面试题
1 判断一字符串是不是对称的,如:abccba
2.用递归的方法判断整数组a[N]是不是升序排列
int is_ascending(int a[],int length){
if(length==1)return 1;
if (a[length-1]>a[length])
{
return 0;
}else
{
return is_ascending(a,length-1);
}
}
96.08年中兴校园招聘笔试题
1.编写strcpy 函数
已知strcpy 函数的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请
编写函数 strcpy
最后压轴之戏,终结此微软等100题系列V0.1版。
那就,
连续来几组微软公司的面试题,让你一次爽个够:
======================
97.第1组微软较简单的算法面试题
1.编写反转字符串的程序,要求优化速度、优化空间。
2.在链表里如何发现循环链接?
3.编写反转字符串的程序,要求优化速度、优化空间。
4.给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里。
5.写一个函数,检查字符是否是整数,如果是,返回其整数值。
(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?)
node* reverse(node* list , node* &head)
{
if
( !list || !list->next )
{
head->next = NULL;
head = list;
return
list;
}
else
{
node* temp = reverse( list->next , head);
temp->next = list;
return
list;
}
}
|
a绳从两头烧,同时b绳从一头烧,当a绳烧尽时,灭掉b绳,同时c绳从两头烧,在c绳烧尽时,b绳从两头烧,结束时即为1小时15分钟。
100.第4组微软面试题,挑战思维极限
1.12个球一个天平,现知道只有一个和其它的重量不同,问怎样称才能用三次就找到那个球。
13个呢?(注意此题并未说明那个球的重量是轻是重,所以需要仔细考虑)(5分钟-1小时)
2.在9个点上画10条直线,要求每条直线上至少有三个点?(3分钟-20分钟)
3.在一天的24小时之中,时钟的时针、分针和秒针完全重合在一起的时候有几次?
都分别是什么时间?你怎样算出来的?(5分钟-15分钟)
终结附加题:
微软面试题,挑战你的智商
==========
说明:如果你是第一次看到这种题,并且以前从来没有见过类似的题型,
并且能够在半个小时之内做出答案,说明你的智力超常..)
1.第一题 . 五个海盗抢到了100颗宝石,每一颗都一样大小和价值连城。他们决定这么分:
抽签决定自己的号码(1、2、3、4、5)
首先,由1号提出分配方案,然后大家表决,当且仅当超过半数的人同意时,
按照他的方案进行分配,否则将被扔进大海喂鲨鱼
如果1号死后,再由2号提出分配方案,然后剩下的4人进行表决,
当且仅当超过半数的人同意时,按照他的方案进行分配,否则将被扔入大海喂鲨鱼。
依此类推
条件:每个海盗都是很聪明的人,都能很理智地做出判断,从而做出选择。
问题:第一个海盗提出怎样的分配方案才能使自己的收益最大化?
倒推法解答即可。
2.一道关于飞机加油的问题,已知:
每个飞机只有一个油箱,
飞机之间可以相互加油(注意是相互,没有加油机)
一箱油可供一架飞机绕地球飞半圈,
问题:
为使至少一架飞机绕地球一圈回到起飞时的飞机场,至少需要出动几架飞机?
(所有飞机从同一机场起飞,而且必须安全返回机场,不允许中途降落,中间没有飞机场)