12个高矮不同的人
阿里巴巴一道笔试题
问题描述: 12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
这个笔试题,很YD,因为把某个递归关系隐藏得很深。<–这是我看到的提示信息–>
这个提示信息很关键,至少知道往什么方向上思考了,避开很多弯路。
分析:
12个人,分成两排,每排都是从矮到高排列,而且第二排的人比站在他前面的人高,如果用一个r[2][6]的数组表示一个排列,那么r[0][0]最矮(小),r[1][5]最高(大)。
三个数组
把这12个人的身高存储在数组h[12]中,最终排列结果存储在r[2][6]中,我们每一次排列都从第一列r[][0]开始,然后依次分配下一列。
每次从数组h[]中选两个数放置在数组r[][]中,为了标记数组h[]中已经使用的元素,定义一个辅助数组used[12]用以标记h[]对应位置有没有被使用。
isPlace()函数
假定数组r[2][6]的分配顺序为从上到下,从左到右,即首先是r[0][0], r[1][0],最后是r[0][5], r[1][5]。
每次我们判断在一个位置r[i]j能否放置hk中的一个数时,要保证如下条件
used[k] = 0
h[k] > r[i][j-1] 如果i>0
r[i][j] > r[i-1][j] 如果i=1
嵌套for循环
数组r[2][6]的每一个位置可以有12个选择(普遍情况,不要去考虑isPlace()失败的发问,r[0][0]只能放最小的,r[1][5]只能放最大的)
我们一次放置一列的两个数,使得从第0列到第col列满足条件。
C语言+递归+回溯
#include<stdio.h> int h[12]={1,2,3,4,5,6,7,8,9,10,11,12}; int used[12]={0}; int r[2][6]; int n = sizeof(h)/sizeof(int); int rows = 2; static int count;//不同的排列数 //打印输出排列结果 void output() { int k,i; for(k=0; k<rows; k++) { for(i=0; i<n/rows; i++) printf("%d,",r[k][i]); printf("\n"); } printf("--------------------\n"); } //判断h[x],h[y]能否放置在r[0][col], r[1][col] int isPlace(int x, int y, int col) { if(!used[x] && !used[y] && h[x]<h[y] && (col==0 ||(col>0 && h[x]>r[0][col-1] &&h[y]>r[1][col-1]))) return 1; return 0; } //在1、2排的第col列放置两个适当的数 void arrange(int col) { if(col==n/rows) { output(); count ++; } else { int i, j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { if(!isPlace(i,j,col)) continue; used[i] = 1; used[j] = 1; r[0][col] = h[i]; r[1][col] = h[j]; arrange(col+1);//递归 used[i] = 0; used[j] = 0;//回溯 } } } } int main() { arrange(0); printf("排列方式有 %d 种.\n",count); return 0; }
结果是132种排列方式。是不是感觉和N-皇后问题的回溯算法很相似,同样有一个isPlace函数,用来决断是否可放置,递归之后有used[i]=0来回溯。
留下评论