什么是8拼图?
给定一个具有8个图块的3×3板(每个图块都有一个1到8的数字)和一个空白空间。目的是使用空白空间按顺序将数字放置在图块上。我们可以将四个相邻的(左,右,上方和下方)磁贴滑动到空白区域。
如何确定给定状态是否可解决?
以下是两个示例,第一个示例可以通过一系列幻灯片达到目标状态。第二个例子不能。
以下是检查8个拼图是否可解决的简单规则。
如果在输入状态下反转数为奇数,则不可能求解8个难题的实例。在上图中给出的示例中,第一个示例具有10个反演,因此可以求解。第二个示例有11个反演,因此无法解决。
什么是反演?
如果图块上的值与它们在目标状态下出现的顺序相反,则一对图块将形成反转。例如,以下8个谜题的实例具有两个反转,(8,6)和(8,7)。
1 2 3
4 _ 5
8 6 7
以下是检查8个拼图的给定实例是否可解决的实现。这个想法很简单,我们在给定的8个谜题中计算倒置数。
C++
// C++ program to check if a given instance of 8 puzzle is solvable or not
#include
using namespace std;
// A utility function to count inversions in given array 'arr[]'
int getInvCount(int arr[])
{
int inv_count = 0;
for (int i = 0; i < 9 - 1; i++)
for (int j = i+1; j < 9; j++)
// Value 0 is used for empty space
if (arr[j] && arr[i] && arr[i] > arr[j])
inv_count++;
return inv_count;
}
// This function returns true if given 8 puzzle is solvable.
bool isSolvable(int puzzle[3][3])
{
// Count inversions in given 8 puzzle
int invCount = getInvCount((int *)puzzle);
// return true if inversion count is even.
return (invCount%2 == 0);
}
/* Driver progra to test above functions */
int main(int argv, int** args)
{
int puzzle[3][3] = {{1, 8, 2},
{0, 4, 3}, // Value 0 is used for empty space
{7, 6, 5}};
isSolvable(puzzle)? cout << "Solvable":
cout << "Not Solvable";
return 0;
}
Java
// Java program to check if a given
// instance of 8 puzzle is solvable or not
class GFG
{
// A utility function to count
// inversions in given array 'arr[]'
static int getInvCount(int[][] arr)
{
int inv_count = 0;
for (int i = 0; i < 3 - 1; i++)
for (int j = i + 1; j < 3; j++)
// Value 0 is used for empty space
if (arr[j][i] > 0 &&
arr[j][i] > arr[i][j])
inv_count++;
return inv_count;
}
// This function returns true
// if given 8 puzzle is solvable.
static boolean isSolvable(int[][] puzzle)
{
// Count inversions in given 8 puzzle
int invCount = getInvCount(puzzle);
// return true if inversion count is even.
return (invCount % 2 == 0);
}
/* Driver code */
public static void main (String[] args)
{
int[][] puzzle = {{1, 8, 2},{0, 4, 3},{7, 6, 5}};
if(isSolvable(puzzle))
System.out.println("Solvable");
else
System.out.println("Not Solvable");
}
}
// This code is contributed by chandan_jnu
Python3
# Python3 program to check if a given
# instance of 8 puzzle is solvable or not
# A utility function to count
# inversions in given array 'arr[]'
def getInvCount(arr) :
inv_count = 0
for i in range(0, 2) :
for j in range(i + 1, 3) :
# Value 0 is used for empty space
if (arr[j][i] > 0 and arr[j][i] > arr[i][j]) :
inv_count += 1
return inv_count
# This function returns true
# if given 8 puzzle is solvable.
def isSolvable(puzzle) :
# Count inversions in given 8 puzzle
invCount = getInvCount(puzzle)
# return true if inversion count is even.
return (invCount % 2 == 0)
# Driver code
puzzle = [[1, 8, 2],[0, 4, 3],[7, 6, 5]]
if(isSolvable(puzzle)) :
print("Solvable")
else :
print("Not Solvable")
# This code is contributed by divyeshrabadiya07.
C#
// C# program to check if a given
// instance of 8 puzzle is solvable or not
using System;
class GFG
{
// A utility function to count
// inversions in given array 'arr[]'
static int getInvCount(int[,] arr)
{
int inv_count = 0;
for (int i = 0; i < 3 - 1; i++)
for (int j = i + 1; j < 3; j++)
// Value 0 is used for empty space
if (arr[j, i] > 0 && arr[j, i] > arr[i, j])
inv_count++;
return inv_count;
}
// This function returns true
// if given 8 puzzle is solvable.
static bool isSolvable(int[,] puzzle)
{
// Count inversions in given 8 puzzle
int invCount = getInvCount(puzzle);
// return true if inversion count is even.
return (invCount % 2 == 0);
}
/* Driver code */
static void Main()
{
int[,] puzzle = new int[3,3]{{1, 8, 2},
{0, 4, 3}, // Value 0 is used for empty space
{7, 6, 5}};
if(isSolvable(puzzle))
Console.WriteLine("Solvable");
else
Console.WriteLine("Not Solvable");
}
}
// This code is contributed by chandan_jnu
PHP
Javascript
输出 :
Solvable
注意,上面的实现使用简单的算法进行反转计数。这样做是为了简化。使用基于合并排序的算法对反转计数,可以将代码优化为O(nLogn)。
这是如何运作的?
该思想基于以下事实:一组移动后反转的奇偶性保持不变,即,如果初始阶段的反转计数为奇数,则在任何移动序列后反转的奇偶性仍为奇数,并且如果反转计数为偶数,则它即使经过任何顺序的移动,仍然保留。在目标状态下,存在0个反转。因此,我们只能从具有反转计数的状态达到目标状态。
反转计数的奇偶性如何不变?
滑动图块时,要么行移动(将左图块或右图块移动到空白空间),要么使列移动(将上图块或下图块移动到空白空间)。
a)行移动不会改变反转计数。请参阅以下示例
1 2 3 Row Move 1 2 3
4 _ 5 ----------> _ 4 5
8 6 7 8 6 7
Inversion count remains 2 after the move
1 2 3 Row Move 1 2 3
4 _ 5 ----------> 4 5 _
8 6 7 8 6 7
Inversion count remains 2 after the move
b)列移动执行以下三个操作之一。
…..(i)将反转计数增加2。请参见以下示例。
1 2 3 Column Move 1 _ 3
4 _ 5 -----------> 4 2 5
8 6 7 8 6 7
Inversion count increases by 2 (changes from 2 to 4)
…..(ii)反转计数减少2
1 3 4 Column Move 1 3 4
5 _ 6 ------------> 5 2 6
7 2 8 7 _ 8
Inversion count decreases by 2 (changes from 5 to 3)
…..(iii)保持反转计数相同。
1 2 3 Column Move 1 2 3
4 _ 5 ------------> 4 6 5
7 6 8 7 _ 8
Inversion count remains 1 after the move