历届试题 九宫重排
时间限制:1.0s 内存限制:256.0MB
问题描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
123.46758
样例输出
3
样例输入
13524678.
46758123.
46758123.
样例输出
22
解题思路: 典型的 bfs , 最坏的情况 9! 最基本的bfs可以过评测。 后面附上双向BFS
1) 单向BFS
import java.util.LinkedList;
import java.util.Scanner;
public class Asist
{
public static final int fac[] = {1,1,2,6,24,120,720,5040,40320,362880};
public static final int move[][] = {{1,0},{-1,0},{0,1},{0,-1}};
public static final int MAX = 1000000;
public static int step = -1;
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String str1 = sc.nextLine();
String str2 = sc.nextLine();
Node start = new Node();
Node end = new Node();
for (int i = 0; i < str1.length(); i++)
{
if (str1.charAt(i) == '.')
{
start.s = new StringBuffer(str1);
start.s.replace(i, i+1, "0");
start.index = i;
start.step = 0;
start.status = getHash(start.s.toString(), 9);
}
if (str2.charAt(i) == '.')
{
end.s = new StringBuffer(str2);
end.s.replace(i, i+1, "0");
end.index = i;
end.step = 0;
end.status = getHash(end.s.toString(), 9);
}
}
if (str1.equals(str2)) System.out.println(0);
else
{
bfs(start, end);
System.out.println(step);
}
}
private static void bfs(Node start, Node end)
{
boolean vis[] = new boolean[MAX];
LinkedList<Node> list = new LinkedList<Node>();
Node cur, next;
cur = getNode(start);
list.add(cur);
while(!list.isEmpty())
{
cur = list.pop();
int x = cur.index / 3;
int y = cur.index % 3;
for (int i = 0; i < 4; i++)
{
int tx = x + move[i][0];
int ty = y + move[i][1];
if (tx > 2 || tx < 0 || ty > 2 || ty < 0) continue;
next = getNode(cur);
next.index = tx * 3 + ty;
next.s.replace(cur.index, cur.index+1, cur.s.charAt(next.index)+"");
next.s.replace(next.index, next.index+1, "0");
next.step++;
next.status = getHash(next.s.toString(), 9);
if (next.status == end.status)
{
step = next.step; return;
}
if (!vis[next.status])
{
vis[next.status] = true;
list.add(next);
}
}
}
}
// 对象的拷贝
private static Node getNode(Node start)
{
Node node = new Node();
node.s = new StringBuffer(start.s.toString());
node.index = start.index;
node.step = start.step;
node.status = start.status;
return node;
}
private static int getHash(String start, int len)
{
int sum = 0;
for (int i = 0; i < len; i++)
{
int count = 0;
for (int j = i + 1; j < len; j++)
if (start.charAt(i) > start.charAt(j)) count++;
sum += count * fac[len-i-1];
}
return sum+1;
}
}
class Node
{
StringBuffer s; // 记录
int index; // 空格
int step; // 步数
int status; // Hash地址
}
2)双向BFS
import java.util.LinkedList;
import java.util.Scanner;
/**
*
* 九宫重排
*
* 双向bfs解法
* @author Xujing
*
*/
public class Main1
{
public static final int fac[] = {1,1,2,6,24,120,720,5040,40320,362880};
public static final int move[][] = {{1,0},{-1,0},{0,1},{0,-1}};
public static final int MAX = 500000;
public static int step = 0;
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String str1 = sc.nextLine();
String str2 = sc.nextLine();
sc.close();
Node start = new Node();
start.s = new StringBuffer(str1);
start.index = start.s.indexOf(".");
start.status = getHash(str1);
start.step = 0;
Node end = new Node();
end.s = new StringBuffer(str2);
end.index = end.s.indexOf(".");
end.status = getHash(str2);
end.step = 0;
long t = System.nanoTime();
if (start.status == end.status) System.out.println(0);
else{
bfs(start, end);
System.out.println(step);
}
System.out.println(System.nanoTime() - t + " ns");
}
private static void bfs(Node start, Node end)
{
int vis1[] = new int[MAX];
int vis2[] = new int[MAX];
LinkedList<Node> list1 = new LinkedList<Node>();
LinkedList<Node> list2 = new LinkedList<Node>();
Node cur1,next1, cur2, next2;
cur1 = getObject(start);
cur2 = getObject(end);
list1.add(cur1);
list2.add(cur2);
while(!list1.isEmpty() && !list2.isEmpty())
{
// 起始状态bfs
cur1 = list1.pop();
int x1 = cur1.index / 3;
int y1 = cur1.index % 3;
for (int i = 0; i < 4; i++)
{
int tx1 = x1 + move[i][0];
int ty1 = y1 + move[i][1];
if (tx1 > 2|| tx1 < 0 || ty1 > 2 || ty1 < 0) continue;
next1 = getObject(cur1);
next1.index = tx1 * 3 + ty1;
next1.s.replace(cur1.index, cur1.index+1, cur1.s.charAt(next1.index)+"");
next1.s.replace(next1.index, next1.index+1, ".");
next1.status = getHash(next1.s.toString());
next1.step++;
if (0==vis1[next1.status])
{
vis1[next1.status] = next1.step;
list1.add(next1);
}
if (vis1[next1.status]!=0 && vis2[next1.status]!=0)
{
step = vis1[next1.status] + vis2[next1.status]; return;
}
}
// 目标状态bfs
cur2 = list2.pop();
int x2 = cur2.index / 3;
int y2 = cur2.index % 3;
for (int i = 0; i < 4; i++)
{
int tx2 = x2 + move[i][0];
int ty2 = y2 + move[i][1];
if (tx2 > 2|| tx2 < 0 || ty2 > 2 || ty2 < 0) continue;
next2 = getObject(cur2);
next2.index = tx2 * 3 + ty2;
next2.s.replace(cur2.index, cur2.index+1, cur2.s.charAt(next2.index)+"");
next2.s.replace(next2.index, next2.index+1, ".");
next2.status = getHash(next2.s.toString());
next2.step++;
if (0==vis2[next2.status])
{
vis2[next2.status] = next2.step;
list2.add(next2);
}
if (vis1[next2.status]!=0 && vis2[next2.status]!=0)
{
step = vis1[next2.status] + vis2[next2.status]; return;
}
}
}
}
private static Node getObject(Node start)
{
Node node = new Node();
node.s = new StringBuffer(start.s.toString());
node.index = start.index;
node.status = start.status;
node.step = start.step;
return node;
}
private static int getHash(String str)
{
int sum = 0;
for (int i = 0; i < str.length(); i++)
{
int count = 0;
for (int j = i+1; j < str.length(); j++)
if (str.charAt(i)>str.charAt(j))count++;
sum += count*fac[str.length()-i-1];
}
return sum+1;
}
}
class Node
{
StringBuffer s; // 路径
int index; // 空格
int status; // Hash值
int step; // 步数
}