拼图游戏可解性判断,自动生成可解拼图

 
拼图游戏都玩过,
对于一个n*m的拼图游戏,我们将按照从左到右,从上到下的顺序给每个分格标注,可得一个二维矩阵。以3*3为例,标注结果如:
[html]  view plain  copy
  1. 0 1 2  
  2. 3 4 5  
  3. 6 7 8  

我们假设最大值为空白。即游戏时的样子是这样的:
[html]  view plain  copy
  1. 0 1 2  
  2. 3 4 5  
  3. 6 7   

但是不是所有的拼图都是有解的。
可解:
[html]  view plain  copy
  1. 6 2 1  
  2. 4 7 5  
  3. 0 3 8  

无解:
[html]  view plain  copy
  1. 4 2 1  
  2. 8 3 6  
  3. 5 0 7  

判断有解:
证明这里就省略了,表示看不懂,可以参加: http://air20.com/archives/323.html
这里说下规律,设两个矩阵A和B。将矩阵从左到右,从上到下排成一个一维数组,设其逆序对的个数加上空白格在原矩阵所在的行列号之和P。若P(A)与P(B)的奇偶性相同,则两个矩阵可以通过拼图游戏进行转换。因此只要计算当前矩阵和正确矩阵的P值判断一下即可。

生成随机可解拼图游戏:
设拼图规模为n*m,用pt[n][m]表示,空白格位于pt[n-1][m-1]。
对于n*m的游戏,生成一个大小为n*m的一维数组data[n*m],空白格在data[n*m-1]。
则 p = n+m+con。其中con为data[0...n*m-2]的逆序对个数。
由于奇数+奇数=偶数,奇数+偶数=奇数,偶数+偶数=偶数,我们知道n+m的奇偶性,因此只要保证con的奇偶性即可。
随机生成data[0...n*m-2]。因为con(data[0...n*m-2])由con(data[0...n*m-4])和con(data[n*m-3...n*m=2])决定,而data[n*m-2]和data[n*m-3]的位置关系,不影响data[0...n*m-4]的奇偶性。
所以交换data[n*m-2]和data[n*m-3]会改变整个数据的逆序对个数的奇偶性。
因此只要根据随机生成的data,适当交换data[n*m-2]和data[n*m-3]的位置即可。。从这个规律也可以看出,随机的矩阵中只有一半是可解的。。
生成代码如下:
[cpp]  view plain  copy
  1. void getKeJiePingTu(int a[vol][col]){                
  2.                  int data[vol*col] = {0};  
  3.                  int maxnumber = vol*col-1;  
  4.                  for (int i=0;i<maxnumber;++i){  
  5.                                 data[i] = i;  
  6.                                  int replacei = rand()%(i+1);  
  7.                                  int t = data[i];  
  8.                                 data[i] = data[replacei];  
  9.                                 data[replacei] = t;  
  10.                 }  
  11.                 data[maxnumber] = maxnumber;  
  12.                  //计?算?逆?序??对?数?y  
  13.                  int coverPairCount = 0;  
  14.                  for (int i=0;i<maxnumber;++i){  
  15.                                  for (int j=i+1;j<maxnumber;++j){  
  16.                                                  if (data[i]>data[j])  
  17.                                                                 coverPairCount++;  
  18.                                 }  
  19.                 }  
  20.                  if ( (coverPairCount&1) == 1){  
  21.                                  int t = data[maxnumber-1];  
  22.                                 data[maxnumber-1] = data[maxnumber-2];  
  23.                                 data[maxnumber-2] = t;  
  24.                 }  
  25.                  int index = 0;  
  26.                  for (int i=0;i<vol;++i){  
  27.                                  for (int j=0;j<col;++j){  
  28.                                                 a[i][j] = data[index++];  
  29.                                 }  
  30.                 }  
  31. }  

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明
九宫格拼图是指在给定的初始状态下,无论怎样移动拼图块,都无法还原成目标状态。在Java中,可以通过以下步骤来判断九宫格拼图是否有: 1. 首先,将九宫格拼图表示为一个一维数组,其中每个元素代表一个拼图块的编号,0表示空白块。 2. 计算初始状态中空白块所在行的逆序数之和,即空白块下方的所有拼图块比上方的拼图块多的个数。 3. 如果初始状态的行数为奇数,则逆序数之和为偶数时,九宫格拼图;逆序数之和为奇数时,九宫格拼图。 4. 如果初始状态的行数为偶数,则逆序数之和加上空白块所在行的行号为奇数时,九宫格拼图;逆序数之和加上空白块所在行的行号为偶数时,九宫格拼图。 下面是一个示例代码,用于判断九宫格拼图是否有: ```java public class PuzzleSolver { public static boolean isSolvable(int[] puzzle) { int inversions = countInversions(puzzle); int blankRow = getBlankRow(puzzle); int size = (int) Math.sqrt(puzzle.length); if (size % 2 == 1) { return inversions % 2 == 0; } else { return (inversions + blankRow) % 2 == 1; } } private static int countInversions(int[] puzzle) { int inversions = 0; int size = puzzle.length; for (int i = 0; i < size - 1; i++) { for (int j = i + 1; j < size; j++) { if (puzzle[i] != 0 && puzzle[j] != 0 && puzzle[i] > puzzle[j]) { inversions++; } } } return inversions; } private static int getBlankRow(int[] puzzle) { int size = (int) Math.sqrt(puzzle.length); for (int i = 0; i < puzzle.length; i++) { if (puzzle[i] == 0) { return size - i / size; } } return -1; } } ``` 使用示例: ```java int[] puzzle = {1, 2, 3, 4, 5, 6, 8, 7, 0}; boolean solvable = PuzzleSolver.isSolvable(puzzle); System.out.println("Is puzzle solvable? " + solvable); ``` 输出结果: ``` Is puzzle solvable? true ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值