关于静态模式数据库(5-5-5),请参见这里(第290页和283页),或者下面有解释。关于什么是15拼图?
我正在创建一个静态模式数据库(5-5-5)。这段代码用于填充第一个表的条目。我通过递归函数insertInDB()
来实现。递归函数的第一个输入是这样的(实际上,输入的拼图是以一维数组的形式包含的。为了便于理解,我将其表示为下面的二维形式)
1 2 3 4
0 6 0 0
0 0 0 0
0 0 0 0
这是我的代码:
class DBClass{ public Connection connection; public ResultSet rs; public PreparedStatement ps1; public PreparedStatement ps2; public int k; String read_statement,insert_statement; public DBClass() { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { connection = DriverManager .getConnection("jdbc:mysql://localhost/feedback?" + "user=ashwin&password=ashwin&autoReconnect=true&useUnicode=true&characterEncoding=utf8&validationQuery=Select 1"); insert_statement="insert into staticpdb1(hash,permutation,cost) values(?,?,?)"; read_statement="select SQL_NO_CACHE * from staticpdb1 where hash=? and permutation= ? LIMIT 1"; ps1=connection.prepareStatement(read_statement, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ps2=connection.prepareStatement(insert_statement); k=0; } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public int updateIfNecessary(FifteenPuzzle sub) { String str=sub.toDBString(); try { ps1.setInt(1, sub.hashcode()); ps1.setString(2,str); rs=ps1.executeQuery(); if(rs.next()) { //如果存在一行,检查成本是否大于sub的成本 int cost=rs.getInt(3); if(sub.g_n<cost) //如果sub的成本小于数据库行的成本 { //替换成本 rs.updateInt(3, sub.g_n); rs.updateRow(); return 1; //仅检查 - 不插入 } else return 0; //不检查 - 返回 } else return 2; //插入并检查 } catch(SQLException e) { System.out.println("here1"+e); System.err.println("报告的递归级别为 "+e.getStackTrace().length); return 0; } finally{ try{ rs.close();} catch(final Exception e1) { System.out.println("here2"+e1); } } } public void insert(FifteenPuzzle sub) { try{ String str=sub.toDBString(); ps2.setInt(1,sub.hashcode()); ps2.setString(2, str); ps2.setInt(3,sub.g_n); ps2.executeUpdate(); ps2.clearParameters(); }catch(SQLException e) { System.out.println("here3"+e); } } public void InsertInDB(FifteenPuzzle sub) throws SQLException { System.out.println(k++); int i; int p=updateIfNecessary(sub); if(p==0) { System.out.println("返回"); return; } if(p==2) { insert(sub); System.out.println("已插入"); } //FifteenPuzzle temp=new FifteenPuzzle(sub.puzzle.clone(),2,sub.g_n); for(i=0;i<sub.puzzle.length;i++) { if(sub.puzzle[i]!=0) { //检查它可以移动到的位置 if(i%4!=0 && sub.puzzle[i-1]==0) //左 { //创建另一个克隆并增加移动次数 FifteenPuzzle temp_inner=new FifteenPuzzle(sub.puzzle.clone(),2,sub.g_n+1); //交换位置 int t=temp_inner.puzzle[i]; temp_inner.puzzle[i]=temp_inner.puzzle[i-1]; temp_inner.puzzle[i-1]=t; InsertInDB(temp_inner); } if(i%4!=3 && sub.puzzle[i+1]==0) //右 { //创建另一个克隆并增加移动次数 FifteenPuzzle temp_inner=new FifteenPuzzle(sub.puzzle.clone(),2,sub.g_n+1); //交换位置 int t=temp_inner.puzzle[i]; temp_inner.puzzle[i]=temp_inner.puzzle[i+1]; temp_inner.puzzle[i+1]=t; InsertInDB(temp_inner); } if(i/4!=0 && sub.puzzle[i-4]==0) //上 { //创建另一个克隆并增加移动次数 FifteenPuzzle temp_inner=new FifteenPuzzle(sub.puzzle.clone(),2,sub.g_n+1); //交换位置 int t=temp_inner.puzzle[i]; temp_inner.puzzle[i]=temp_inner.puzzle[i-4]; temp_inner.puzzle[i-4]=t; InsertInDB(temp_inner); } if(i/4!=3 && sub.puzzle[i+4]==0) //下 { //创建另一个克隆并增加移动次数 FifteenPuzzle temp_inner=new FifteenPuzzle(sub.puzzle.clone(),2,sub.g_n+1); //交换位置 int t=temp_inner.puzzle[i]; temp_inner.puzzle[i]=temp_inner.puzzle[i+4]; temp_inner.puzzle[i+4]=t; InsertInDB(temp_inner); } } }
类中的函数insertInDB(FifteenPuzzle fp)是递归函数,并首先从主函数中调用,传入的十五拼图参数数组(puzzle
是FifteenPuzzle
类的整数数组字段)为 – 1,2,3,4,0,6,0,0,0,0,0,0,0,0,0,0
(与上面的矩阵相同)。在解释其他函数之前,我将简要解释什么是静态模式数据库;(因为下面的评论)
什么是15拼图的(5-5-5)静态模式数据库?
模式数据库是用于解决十五拼图的启发式方法(可以是任何拼图。但这里我只谈论15拼图)。启发式是一个用于确定下一个要扩展的状态的数字。它就像每个状态的成本。这里的状态是15拼图的排列。对于简单的拼图,如8拼图,启发式可以是曼哈顿距离。它给出每个错位的瓷砖到达其目标位置所需的最小移动次数。然后将所有瓷砖的曼哈顿距离加起来,得到该瓷砖的成本。曼哈顿距离给出了达到目标状态所需移动次数的下限估计,即你不能以少于曼哈顿距离的移动次数达到目标状态。但是曼哈顿距离并不是一个很好的启发式方法,尽管是可接受的,因为它没有考虑附近的其他瓷砖。如果一个瓷砖要移动到它的目标位置,附近的瓷砖也必须移动,移动次数会增加。因此,对于这些拼图,实际成本通常远大于曼哈顿距离。
为了克服这一点(曼哈顿距离)并考虑其他瓷砖,引入了模式数据库。静态模式数据库保存子问题或一组瓷砖达到其目标状态的启发式方法。由于您正在计算使这些瓷砖组达到其目标状态所需的移动次数,因此当移动一个瓷砖时,该组中的其他瓷砖将被考虑在内。因此,这是一个更好的启发式方法,并且通常总是大于曼哈顿距离。
5-5-5静态模式只是静态模式数据库的一种形式,其中组的数量为3,其中两个组各包含5个瓷砖,第三个组包含6个(第6个是空白瓷砖)。
其中一个组是这个矩阵:
1 2 3 4
0 6 0 0
0 0 0 0
0 0 0 0
我正在计算这个组的所有排列达到上述配置的启发式/移动次数,并将它们插入我的数据库。
可能的组合总数(也是数据库中的行数)是
16!/(16-5)! = 524160
现在,其他函数 – updateIfNecessary(FifteenPuzzle)
– 此函数检查传入的FifteenPuzzle对象的数组是否已经存在于数据库中。如果已经存在于数据库中,它会检查当前对象的成本是否小于数据库中的成本。如果是,则用当前成本替换它,否则不做任何操作。函数 –insert(FifteenPuzzle)
插入一个新的排列及其成本。
注意: fifteenuzzle.g_n
是拼图的成本。对于表示上述矩阵的初始拼图,成本是0
,每次移动成本增加1
。
我已将堆栈大小设置为-Xss128m
(1024, 512和256会导致致命错误)用于运行配置中的堆栈大小。
目前递归次数或深度是7,500,000
且还在增加(即System.out.println(k++);
的值)。
可能的组合总数是
16!/(16-5)! = 524160
但深度已经达到7,500,000。这是由于生成重复状态。目前数据库中的条目数为513423。你可能会认为现在只剩下10,000个条目要填充。但现在条目的生成速度已经急剧下降,大约每30分钟一个条目。这样永远也完不成。
我需要一个实用的解决方案 – 无论是否使用递归。这可能吗?
回答: