突发奇想
首先这个题目有点大,但我实在想不出更好的标题了,这一切也是由于最近与小伙伴们讨论双色球,简单来说双色球就是一种排列组合小游戏,但又区别于全排列,它只针对数值而不针对位置,而其又区别蓝球与红球,那么我们很简单的就可以算出其全组合的可能数值,即红球33选6,33!/(6! * (33-6)!) = 1107568,蓝球16选1,全组合就是1107568 * 16 = 17721088,想一想这也确实很夸张,别说中头奖了,甚至中三等奖也是低概率事件,那么我们是否有办法提高中奖概率呢,个人认为肯定是有的,毕竟双色球只是一种伪随机.
程序实现
经过挖掘与分析,貌似能提高双色球中奖概率的条件有以下几种,例如红球分区,和值,跨度,奇偶比,质合比,012路比等等,那么我们可以将这类限制抽象成条件,但前提是我们需要将所有的组合全部列举出来,然后通过条件去缩小范围,这里我们有了第一个问题,即生成红球的所有组合,然后输出到一个文件里,代码看起来应该是这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class Combination { public final static int[] list = new int[] {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}; // 取6个红球 public final static int M = 6; public ArrayList<String> result = new ArrayList<String>(); public static void main(String[] args) throws IOException { Combination c = new Combination(); // TODO 生成红球的所有组合 c.combine(); FileUtils.writeLines(new File("ssq.txt"), c.result); System.out.println("total:" + c.result.size()); } } |
这里我们主要难点就是生成全部组合可能,如何生成这种组合呢,我们可以先用一个笨办法,就是枚举,我们先缩小其可选范围也取值,即在5个数中选取2个,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public void test() { int[] ALL = new int[] {1, 2, 3, 4, 5}; List<String> list = new ArrayList<String>(); for (int a = 0; a < 5; a++) { StringBuilder sba = new StringBuilder(); sba.append(ALL[a]); for (int b = 1; b < 5; b++) { if (ALL[a] < ALL[b]) { StringBuilder sbb = new StringBuilder(sba); sbb.append(ALL[b]); list.add(sbb.toString()); System.out.println(sbb.toString()); } } } System.out.println("total:" + list.size()); } |
首先这里我们可以先清楚的看出选几个球就需要循环几次,那么我们自然想到需要递归,而每进下一次循环前先把本次循环的数值增加至StringBuilder中,一旦进入下次循环,先判断当前值是否大于一上层的数值,因为我们只选数值,没有必要关注位置,这样由于最外层数值由小到大,那么内层数值只需要大于外层数值即可,我们将代码补全
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 |
public class Combination { public final static int[] list = new int[] {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}; // 取6个红球 public final static int M = 6; public ArrayList<String> result = new ArrayList<String>(); public static void main(String[] args) throws IOException { Combination c = new Combination(); c.combine(list, new StringBuilder(), 0, M); FileUtils.writeLines(new File("ssq.txt"), c.result); System.out.println("total:" + c.result.size()); } private void combine(int[] list, StringBuilder sb, int index, int count) { for (int i = index; i < list.length; i++) { StringBuilder tmp = null; tmp = new StringBuilder(sb); if (count == 1) { result.add(tmp.append(list[i]).toString()); } else { tmp.append(list[i]).append(","); combine(list, tmp, i + 1, count - 1); } } } } |
这样我们就能生成全部的红球组合.
有了全部组合,再根据条件过滤就比较简单了,我们先抽象出一个接口LotteryCondition,它只有一个功能,就是判断条件是否符合
1 2 3 4 5 6 |
public interface LotteryCondition { public boolean match(List<Integer> num); } |
比如我们需要加一个和值区间的条件应该是这样
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 |
public static class TotalCondition implements LotteryCondition { private int min; private int max; public TotalCondition(int min, int max) { this.min = min; this.max = max; } public int getMin() { return min; } public void setMin(int min) { this.min = min; } public int getMax() { return max; } public void setMax(int max) { this.max = max; } @Override public boolean match(List<Integer> num) { int r = 0; for (Integer i : num) { r += i; } return r >= min && r <= max; } } |
使用的话这样就行了
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 |
public static void main(String[] args) throws Exception { // 合值条件 totalCondition = new TotalCondition(100, 120); // 跨度条件 ... // 区间条件 ... // 奇偶条件 ... // 质合条件 ... // MOD条件 ... List<String> result = new ArrayList<String>(); List<String> lines = FileUtils.readLines(new File("ssq.txt"), "utf-8"); for (String s : lines) { String[] t = s.split(","); List<Integer> line = new ArrayList<Integer>(); for (String num : t) { line.add(Integer.valueOf(num)); } check(line, result); } FileUtils.writeLines(new File("r.txt"), result); } private static void check(List<Integer> line, Collection<String> result) { boolean totalConditionFlag = false; if (totalCondition != null && totalCondition.match(line)) { totalConditionFlag = true; } // 其它条件匹配 ... } |
当然写这篇文章的目的并不是要中双色球,而是一种思维习惯,生活中很多问题都可以用程序来处理,哪怕你只是实现其中的某一些功能时,那种满足感只有程序猿自己才能感受的到!
你肿了没有
呵呵,大奖没有,小奖不少,娱乐而已~