点击注册
点击注册
.

排列组合数的产生


发布日期:2022-03-20 09:44    点击次数:135


最近在写一个小项目,计算极大似然估计的时候,需要生成一些组合数,就是说给定一列数字,比如(1,1,2,3,1),产生这些数字的不重复的排列组合:(1 1 1 2 3)(1 1 2 3 1)(1 2 3 1 1)(2 3 1 1 1)(1 1 2 1 3)(1 2 1 3 1)(2 1 3 1 1)(1 2 1 1 3)(2 1 1 3 1)(2 1 1 1 3)(1 1 1 3 2)(1 1 3 2 1)(1 3 2 1 1)(3 2 1 1 1)(1 1 3 1 2)(1 3 1 2 1)(3 1 2 1 1)(1 3 1 1 2)(3 1 1 2 1)(3 1 1 1 2)应该有种。一开始我在matlab里面写,最自然的想法就是,直接用matlab的命令,产生排列组合数,然后把重复的去掉:unique(perms([1 1 2 2 3]),'rows') 结果因为我的规模比较大,大约70个数字的向量,假如有个1,个2...那么全部存储下来,有。我用这个命令计算,Matlab直接告诉我,超过最大行数。。。但是实际上,我最终的计算结果,只要针对每一种可能的排列组合计算一个数,然后加总就可以了。想了好久没想到什么好的办法。想了一下可以用递归,但是还是没解决空间的问题。求救于万能的知乎,立马就有人给了我靠谱的答案:请教产生排列组合的算法?当然,最靠谱的答案不在答案里,在题目的评论里。按照他给的算法名字我去google,果真查到了可行的算法:http://nayuki.eigenstate.org/page/next-lexicographical-permutation-algorithm,而且连现成的C代码都有了。既然这样,问题就解决了:#include <stddef.h> #include <stdio.h> #include <gsl/gsl_sort_int.h> int next_permutation(int *array, size_t length) { size_t i, j; int temp; // Find non-increasing suffix if (length == 0) return 0; i = length - 1; while (i > 0 && array[i - 1] >= array[i]) i--; if (i == 0) return 0; // Find successor to pivot j = length - 1; while (array[j] <= array[i - 1]) j--; temp = array[i - 1]; array[i - 1] = array[j]; array[j] = temp; // Reverse suffix j = length - 1; while (i < j) { temp = array[i]; array[i] = array[j]; array[j] = temp; i++; j--; } return 1; } void main(){ int a[]={1,1,2,2,3}; int i; gsl_sort(a,0,5); do{ printf("("); for (i=0;i<5;++i){ printf("%d,",*(a+i)); } printf(")\n"); }while (next_permutation(a,5)); } Ok,极大似然的目标函数就可以用C重写了,既解决了空间的问题,也同时解决了这个似然函数循环太多太慢的问题。

玩麻将并不是单纯地靠运气,更多的是在比拼玩家的智慧。即便是拿到一幅好牌,如果没有任何的技巧,我们还是难以吃胡。麻将听牌高手认为,学会听牌是最为关键的一步。听一张牌和听两张牌,三张牌之间有着极大的区别。当然了,如果手上的牌非常烂,那么千万要忍耐,运用你的智慧,让局势最大限度地扭转,那么你就成功了。一旦你决定好了听牌,千万不要随便改变自己的牌局,否则将会影响局势的变化。

7.杠“五梅花”,大多数认可的是单调或卡五筒,也有的是只要五筒就行,前者易引起争议,故以和牌时能组成单调或卡五筒就视为“五梅花”为妥。