猜数字游戏穷举法(迅雷水晶矿场中的游戏求解)
来源:互联网 发布:高校金融教学软件 编辑:程序博客网 时间:2024/06/13 18:06
猜数字是一个比较经典的游戏。有若干的空,每个空可以填入若干种数字,每次填入数字后,提示有几个数字是正确的,有几个数字位置填写对了。如果位置正确的数字和填入数字个数相等则得到正确答案。
这里只针对一种简单的情况(有3个空,每个空可以填入0-3中的一个数字)使用穷举法求解。想了解更多可以看论文https://arxiv.org/pdf/1305.1010.pdf
3个空,每个空填入0-3的数字,则所有的情况有4*4*4=64种可能。随便猜一个数,返回结果可以表示成(0,0)(1,0)(1,1)(2,0)(2,1)(2,2)(3,0)(3,1)(3,2)(3,3)(4,0)(4,1)(4,2)(4,3)(4,4)中的一种,(1,0)表示有1个颜色正确0个位置正确。随便猜一个数字就可以把64中可能分配到不同的结果集中,如果某个结果集中只有一种可能,表示这次猜测能得到该结果,如果结果集中有多种可能则继续猜测。
随便猜测时把64种可能都试一遍,找到平均猜测次数最小的就是我们想要的答案了。代码如下:
import java.util.ArrayList;import java.util.List;import java.util.Scanner;//存放当前的状态class Point{ final int N = 3;//该类只能操作3位数的猜数字游戏 int[] colors = new int[N]; Point(){} Point(int i,int j,int k){ this.colors[0] = i; this.colors[1] = j; this.colors[2] = k; } //获取正确数字个数 public int rightNumber(Point p){ int num = 0; boolean a[] = new boolean[N]; for(int i=0;i<N;i++){ a[i] = false; } for(int i=0;i<N;i++){ for(int j=0;j<N;j++){ if(!a[j]){ if(this.colors[i]== p.colors[j]){ num++; a[j]= true; break; } } } } return num; } //位置和颜色都正确的个数 public int rightStatus(Point p){ int num = 0; for(int i=0;i<N;i++){ if(this.colors[i] == p.colors[i]){ num++; } } return num; }}//查找最优方法public class GetBestWay { /** * 根据猜测进行分组 * @param possble 所有的可能 * @param rule 如果用户输入的是rule,把所有可能进行分组 * @return 所有分组的情况 */ public static List<ArrayList<Point> > getPossibleArray(List<Point> possble,Point rule){ List<ArrayList<Point> > eligible = new ArrayList<ArrayList<Point> >(); //因为只有3个数字,颜色正确个数有4种可能, //颜色和位置都正确右4种可能,组合起来有16种可能 for(int i=0;i<16;i++){ ArrayList<Point> temp = new ArrayList<Point>(); eligible.add(temp); } for(int i=0;i<possble.size();i++){ int r1 = possble.get(i).rightNumber(rule); int r2 = possble.get(i).rightStatus(rule); //把所有可能分配到不同的集合中 eligible.get(r1*4+r2).add(possble.get(i)); } return eligible; } /** * 已知用户输入和正确数字个数与正确位置个数,求所有可能 * @param possble 输入所有的可能 * @param rule 用户输入 * @param result result[0]表示正确数字个数,result[1]表示位置正确个数 * @return 根据正确数字个数和正确位置个数,有哪些可能能满足 */ public static List<Point> getPossible(List<Point> possble,Point rule,int[] result){ List<Point> eligible = new ArrayList<Point>(); if(possble.size()==1){ return eligible; } for(int i=0;i<possble.size();i++){ int r1 = possble.get(i).rightNumber(rule); int r2 = possble.get(i).rightStatus(rule); //与result相符,添加到结果集中 if(r1 == result[0] && r2 == result[1]){ eligible.add(possble.get(i)); } } return eligible; } //打印所有可能性 public static void print(List<Point> possble){ for(int i=0;i<possble.size();i++){ for(int j=0;j<possble.get(i).colors.length;j++){ System.out.print(possble.get(i).colors[j]); System.out.print(" "); } System.out.print("; "); } System.out.println(); } /** * 寻找最优解 * @param possible 所有的可能 * @param bestPoint 返回最优选择 * @return 最优选择平均查找次数 */ public static double findBestPoint(List<Point> possible,Point bestPoint){ int n = possible.size(); if(n==0) return 0; if(n==1){ bestPoint.colors = possible.get(0).colors; return 1; } double min = 999999; //因为穷举法速度太慢,这里使用了贪心策略。因为该贪心方法最后求得的结果也是206/64,是可以的 for(int i=0;i<n;i++){ double result = 1; Point rule = possible.get(i); List<ArrayList<Point> > possibleList = getPossibleArray(possible,rule); //第16种是正确个数和位置都为3,也就是得到正确结果,不用继续查找 for(int j=0;j<15;j++){ List<Point> temp = possibleList.get(j); if(temp.size()!=0){ result+=temp.size()/(double)n*findBestPoint(temp,new Point()); } } if(min>result){ min = result; bestPoint.colors = rule.colors; } } return min; } public static void main(String[] args) { Scanner cin = new Scanner(System.in); List<Point> possible = new ArrayList<Point>(); //初始化,有三个数字要猜。每个数字是0-3中的一种 for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ for(int k=0;k<4;k++){ Point t = new Point(i,j,k); possible.add(t); } } } Point bestPoint = new Point(); int[] rightNum = new int[2]; while(possible.size()>0){ if(possible.size()==1){ System.out.println("当前只有一个选择"); print(possible); break; } System.out.println("当前集合中包含所有可能为:"); print(possible); //根据当前情况查找最优解 double result = findBestPoint(possible,bestPoint); System.out.println("还需要的平均步数为:"+result); System.out.println("推荐最优选择为:"+ bestPoint.colors[0]+" "+bestPoint.colors[1]+" "+bestPoint.colors[2]); System.out.println("你的选择是:"); bestPoint.colors[0] = cin.nextInt(); bestPoint.colors[1] = cin.nextInt(); bestPoint.colors[2] = cin.nextInt(); System.out.println("输出结果是:"); rightNum[0] = cin.nextInt(); rightNum[1] = cin.nextInt(); possible = getPossible(possible, bestPoint, rightNum); } System.out.println("结束"); }}
阅读全文
0 0
- 猜数字游戏穷举法(迅雷水晶矿场中的游戏求解)
- 填数字游戏求解
- 填数字游戏求解
- 填数字玩游戏——穷举法演示
- 穷举法猜数字
- GSM中的数字游戏
- 穷举法猜数字(2)
- 穷举法:填运算符游戏
- 实现24点游戏-穷举法
- 文曲星中的猜数字游戏 python 实现
- 猜数字游戏(html)
- 猜数字游戏(javascript)
- 猜数字游戏(java)
- 猜数字游戏(jackpot)
- 游戏中的数字字体选择
- 游戏_猜数字
- 猜数字游戏
- 猜数字游戏
- mysql exists 和 in的效率比较
- echarts
- 机器视觉按需求选择工业相机的方法
- Android Camera 系统架构源码分析(1)---->Camera的初始化
- 数据库主从复制的读写分离实现,调度器实现高可用
- 猜数字游戏穷举法(迅雷水晶矿场中的游戏求解)
- 笔记9
- Error:Failed to complete Gradle execution. Cause: services.gradle.org
- mybatis判断用insert还是update
- 大量养老金蒸发!只够16个月存活?
- Missing artifact javax.jms:jms:jar: Missing artifact com.sun.jdmk Missing artifact com.sun.jmx:jmxri
- LeetCode 2.Add Two Numbers
- Dubbo架构的学习之旅
- C++ 升级编译器gcc 4.7或者以上版本