12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种? (Java版)
思路: 从网上看了半天人家的分析,终于看明白了,在这里记录一下自己的思路
先用一组数来代表这12个人, 1,2,3,4,5,6 7,8,9,10,11,12 排成两排,每排要递增排列,且对应位置第二排要大于第一排,则可以是
1 2 3 4 5 6 => 第一排的数用0来表示,第二排的数用1来表示,则这个数组序列就是 000000 111111
7 8 9 10 11 12
也可以是
1 3 5 7 9 11 => 这个数组序列就是010101 010101
2 4 6 8 10 12
所以对于任意排序 只要有对应的0和1的序列就可以, 就是有一个0就必须对应的有一个1,
比如 000111000111就可以 对应的排队是 123789 - 456 10 11 12 , 但是有个条件需要满足,就是序列是递增,且第二排要大于第一排
这样问题其实转化为了求12个数的所有可能得入栈和出栈顺序,0代表入栈,1代表出栈
解决方案:首先12个数可以构成所有的0和1的组合是1<<12-1 = 4095, 我们需要依次遍历这4095个数,对于每个数的二进制表示,我们首先需要知道是否满足上述的条件,即肯定要出现六个1, 然后对满足含有六个1的数,对其分成两组,第一组是左侧的六位,第二组是右侧的六位,如果第二组的每个位置的数都大于第一组,则这个数就是我们要找的
1 void catalan(){ 2 int num; 3 int[] front = new int[6]; 4 int[] back = new int[6]; 5 int counter = 0; 6 int i, j , k; 7 for(num = 0; num < (1<<12); num++){ 8 //是否含有六个1? 9 if(bitCount(num) == 6){ 10 i = j = 0; 11 12 for(k = 11; k >=0; k--){ 13 //填充前后排 14 if((num & (1<<k)) == 0){ 15 //从左到右扫描num,如果碰见的是0,即num&(1<<k)==0,则填充前排对应的位置 16 //因为我们要从右到左扫描num,所以k是从11开始,这样的话1<<11才能落在num的最高位 17 front[i++] = 11-k; 18 }else{ 19 //如果碰见的不是是0,即num&(1<<k)!=0,则填充后排对应的位置 20 back[j++] = 11-k; 21 } 22 } 23 boolean ok = true; 24 //前后排填充完毕,开始判断是否符合前排要低于后排的条件 25 for(int m = 0; m < 6; m++){ 26 if(front[m] > back[m]){ 27 ok = false; 28 break; 29 } 30 } 31 32 if(ok){ 33 logBin(num); 34 counter++; 35 } 36 } 37 } 38 39 System.out.println("TOTAL: " + counter); 40 } 41 42 private int bitCount(int n){ 43 int counter = 0; 44 while(n>0){ 45 n &= (n-1); 46 counter++; 47 } 48 return counter; 49 } 50 51 private void logBin(int n){ 52 System.out.println(Integer.toBinaryString(n)); 53 }
参考: http://blog.csdn.net/hackbuteer1/article/details/7450250