蓝桥杯 卡片换位

题目描述:

卡片换位

你玩过华容道的游戏吗?

这是个类似的,但更简单的游戏。

看下面 3 x 2 的格子

+---+---+---+

|  A  |  *   |  *   |

+---+---+---+

|   B  |      |  *  |

+---+---+---+

在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。还有一个格子是空着的。你可以把一张牌移动到相邻的空格中去(对角不算相邻)。游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。

输入格式:输入两行6个字符表示当前的局面

输出格式:

一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)

例如,输入:

* A

**B

程序应该输出:

17

再例如,输入:

A B

***

程序应该输出:

12

 思路:

这道题从字面意思是交换a和b,但是根据规则移动的条件只能移动空格周围的卡片。所以基本等价于移动空格,把各种情况遍历一遍找到一种a和b互换的情况。

由于空格只能移动到相邻位置,所以思路也就明确了可以用广度优先搜索。

空格可以移动有四个方位,上下左右。每移动一次就保存移动后的卡片排序,并且移动到该状态需要的步数是移动前的需要的步数加1.

终将有一次会找到一个卡片序列使得a和b相对起始序列是互换的。

简易代码版:


import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

public class ExchangeAB {
	public static void main(String[] args) {
		String in = "A B***";
		int aOrigin = in.indexOf("A");
		int bOrgin = in.indexOf("B");
		// 保存到某个局面需要的步数
		HashMap save = new HashMap<>();
		// 广度优先的队列
		Queue queue = new LinkedList<>();
		queue.add(in);
		save.put(in, 0);
		// 移动的方向上下左右
		int[][] move = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
		// 广度优先固定格式
		while (!queue.isEmpty()) {
			String nowStr = queue.poll();
			int nowStep = save.get(nowStr);
			// 如果A和B已经交换直接输出
			if (nowStr.indexOf("B") == aOrigin && nowStr.indexOf("A") == bOrgin) {
				System.out.println(nowStep);
				return;
			}
			// 定位到空格的位置
			int spacePos = nowStr.indexOf(" ");
			int x = spacePos / 3;
			int y = spacePos % 3;
			char[] nowArr = nowStr.toCharArray();

			// 向周围扩散
			for (int[] arr : move) {
				int tempx = x + arr[0];
				int tempy = y + arr[1];

				if (tempx >= 0 && tempx < 2 && tempy >= 0 && tempy < 3) {
					// 移动空格位置
					exchange(x, y, tempx, tempy, nowArr);
					String tempStr = String.valueOf(nowArr);
					if (save.get(tempStr) == null) {// 如果这个局面没来过则添加到队列
						queue.add(tempStr);
						save.put(tempStr, nowStep + 1);
					}
					// 复原空格位置方便给下个方向移动
					exchange(x, y, tempx, tempy, nowArr);
				}

			}
		}
	}

	public static void exchange(int x1, int y1, int x2, int y2, char[] arr) {
		int pos1 = x1 * 3 + y1;
		int pos2 = x2 * 3 + y2;
		char temp = arr[pos1];
		arr[pos1] = arr[pos2];
		arr[pos2] = temp;
	}
}

详细代码版: 

package real;

import java.awt.Point;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

public class CardMove {
//有四个移动方位
	public static final int[][] move = { { 1, 0 }, { -1, 0 }, { 0, -1 },
			{ 0, 1 } };

	public static void main(String[] args) {
		String a = "* A**B";//起始顺序(删除换行)
		Queue queue = new LinkedList();
		HashMap qmap = new HashMap();
//保存初始状态卡片A和B的位置
		int posia = a.indexOf('A');
		int posib = a.indexOf('B');
		Point preblank = new Point();
		Point blank = new Point();
//广度优先搜索起点是初始的卡片顺序
		queue.add(a);
//保存初始状态顺序,到达该状态需要0步
		qmap.put(a, 0);
		String temp;
//广度优先搜索固定套路^_^一个循环
		while (!queue.isEmpty()) {
//从队列中拿一个卡片序列出来
			a = queue.poll();
			temp = a;
//判断当前卡片顺序是否满足条件(a,b相对于初始顺序互换了)
			if (a.charAt(posib) == 'A' && a.charAt(posia) == 'B') {
				System.out.println(qmap.get(a));
				break;
			}
//找到空格所在位置方便进行移动遍历
			int posiblank = a.indexOf(' ');
//计算出空格坐标
			preblank.x = posiblank / 3;
			preblank.y = posiblank % 3;
//进行移动遍历,空格有四个方向可以走上下左右
			for (int[] arr : move) {
				blank.x = preblank.x + arr[0];
				blank.y = preblank.y + arr[1];
//判断移动后的目标位置是否合法(是不是出了矩阵)
				if (blank.x >= 0 && blank.x <= 1 && blank.y >= 0
						&& blank.y <= 2) {
//把字符串转字符数组,方便进行互换操作
					char[] achar = a.toCharArray();
					int tempindex = blank.x * 3 + blank.y;
//将空格移动到目标位置(就是将目标位置和空格交换)
					char tempchar = achar[tempindex];
					achar[tempindex] = achar[posiblank];
					achar[posiblank] = tempchar;
//判断移动后的卡片序列是不是以前就走过了,走过了就不用再走了
					if (qmap.get(String.valueOf(achar)) != null)
						continue;
//把产生的新的序列保存下来,到的新的序列所需要的步数是老的序列的步数+1
					qmap.put(new String(achar), qmap.get(temp) + 1);
//将新的序列加入到队列中,用于后面的搜索
					queue.add(new String(achar));
				}
			}
		}

	}
}

 

转载于:https://my.oschina.net/yuanmuou/blog/871607

你可能感兴趣的:(数据结构与算法,java)