2014 WAP校园招聘笔试题1

Abstract
We are planning an orienteering game.
The aim of this game is to arrive at the goal (G) from the start (S) with the shortest distance.
However, the players have to pass all the checkpoints (@) on the map.
An orienteering map is to be given in the following format.
########
#@....G#
##.##@##
#..@..S#
#@.....#
########
In this problem, an orienteering map is to be given.
Calculate the minimum distance from the start to the goal with passing all the checkpoints.
Specification
* A map consists of 5 characters as following.
You can assume that the map does not contain any invalid characters and
the map has exactly one start symbol 'S' and exactly one goal symbol 'G'.
* 'S' means the orienteering start.
* 'G' means the orienteering goal.
* '@' means an orienteering checkpoint.
* '.' means an opened-block that players can pass.
* '#' means a closed-block that players cannot pass.
* It is allowed to move only by one step vertically or horizontally (up, down, left, or right) to the
next block.
Other types of movements, such as moving diagonally (left up, right up, left down and right down)
and skipping one or more blocks, are NOT permitted.
* You MUST NOT get out of the map.
* Distance is to be defined as the number of movements to the different blocks.
* You CAN pass opened-blocks, checkpoints, the start, and the goal more than once if necessary.
* You can assume that parameters satisfy following conditions.
* 1 <= width <= 100
* 1 <= height <= 100
* The maximum number of checkpoints is 18.
* Return -1 if given arguments do not satisfy specifications, or players cannot arrive at the goal

from the start by passing all the checkpoints.


import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Scanner;

class node {
	int x, y;
	int index;
	int step;
};

/**
 * 状态压缩DP,总共的状态数量为2^(checkPointsNum+1)个
 * 
 * @created Oct 29, 2014
 * @author  chenshanfu
 */
public class Orienteering_ori {
	private static int height, width;
	private static int[][] shortestDistance;// checkPoints之间的最短距离
	private static int[][] f;// f[k][state] 到达第k个点的所经过的状态为state的
	private static int checkPointsNum;
	private static int stateNum;
	private static boolean[][] isvisited;//记录isvisited[i][j]是否已经遍历过

	// 增加一层映射关系,@坐标-->index 映射
	private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();
	private static node startPoint = new node();
	private static node endPoint = new node();
	private static char[][] a;// 原始地图
	private static int[][] dir = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };//可以遍历的4个方向
	private static boolean isException;//输入的参数异常
	private static int startPointsNum = 0;
	private static int endPointsNum = 0;

	/**
	 * 读取数据,同时进行参数初始化
	 * 
	 * @created Oct 29, 2014
	 * @author  chenshanfu
	 */
	@SuppressWarnings("resource")
	public static void init() {
		Scanner input = new Scanner(System.in);
		String line = "";
		line = input.nextLine().trim();
		if (line.split(" ").length != 2) {
			isException = true;
		}
		else {
		width = Integer.parseInt(line.split(" ")[0]);
		height = Integer.parseInt(line.split(" ")[1]);
		if (width < 1 || width > 100 || height < 1 || width > 100) {
			isException = true;
		}

		a = new char[height][width];
		int checkPointsIndex = 0;
		for (int i = 0; i < height; i++) {
			line = input.nextLine().trim();
			if (width != line.length()) {
				isException = true;
				break;
			}
			for (int j = 0; j < width; j++) {
				char c = line.charAt(j);
				a[i][j] = c;
				int tmp = i * width + j;
				if (c == '@') {
					map.put(tmp, ++checkPointsIndex);
				} else if (c == 'S') {
					startPoint.x = i;
					startPoint.y = j;
					startPoint.step = 0;
					startPoint.index = tmp;
					startPointsNum++;
				} else if (c == 'G') {
					endPoint.x = i;
					endPoint.y = j;
					endPoint.step = 0;
					endPoint.index = tmp;
					endPointsNum++;
				}
			}
		}
		checkPointsNum = checkPointsIndex;
		if (startPointsNum != 1 || endPointsNum != 1 || checkPointsNum < 0
				|| checkPointsNum > 18) {
			isException = true;
		}
		stateNum = (int) Math.pow(2.0, 1.0 * checkPointsNum + 1);
		map.put(startPoint.index, 0);
		map.put(endPoint.index, checkPointsNum + 1);
		/*
		 * System.out.println("stateNum:"+stateNum);
		 * System.out.println("checkPointsNum:"+checkPointsNum); for(Integer
		 * s:map.keySet()){ System.out.println("**"+s+":"+map.get(s)); }
		 */

		f = new int[checkPointsNum + 2][stateNum];
		isvisited = new boolean[height][width];

		shortestDistance = new int[checkPointsNum + 2][checkPointsNum + 2];// shortestDistance
																			// 初始
		for (int i = 0; i < checkPointsNum + 2; i++) {
			for (int j = i + 1; j < checkPointsNum + 2; j++) {
				shortestDistance[i][j] = Integer.MAX_VALUE;
				shortestDistance[j][i] = Integer.MAX_VALUE;
			}
		}
		}
	}

	/**
	 * 
	 * 计算初始节点s到其他checkPoints之间的最短距离,利用BFS实现
	 * @param s
	 * @created Oct 29, 2014
	 * @author  chenshanfu
	 */
	public static void bfs(node s) {
		LinkedList<node> queue = new LinkedList<node>();
		queue.add(s);
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				isvisited[i][j] = false;
			}
		}
		isvisited[s.x][s.y] = true;
		while (!queue.isEmpty()) {
			node front = new node();
			front = queue.getFirst();
			queue.removeFirst();
			for (int i = 0; i < 4; i++) {
				node tmpnode = new node();
				tmpnode.x = front.x + dir[i][0];
				tmpnode.y = front.y + dir[i][1];
				if (tmpnode.x >= 0 && tmpnode.x < height && tmpnode.y >= 0
						&& tmpnode.y < width
						&& !isvisited[tmpnode.x][tmpnode.y]
						&& a[tmpnode.x][tmpnode.y] != '#') {
					isvisited[tmpnode.x][tmpnode.y] = true;
					tmpnode.step = front.step + 1;
					tmpnode.index = tmpnode.x * width + tmpnode.y;
					queue.add(tmpnode);
					if (map.get(tmpnode.index) != null) {
						shortestDistance[map.get(s.index)][map
								.get(tmpnode.index)] = tmpnode.step;
					}
				}

			}
		}
	}

	/**
	 * 计算所有的checkPoints之间的最小距离
	 * 
	 * @created Oct 29, 2014
	 * @author  chenshanfu
	 */
	public static void getMinDistance() {
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				if (a[i][j] == '@' || a[i][j] == 'S' || a[i][j] == 'G') {
					node tmpNode = new node();
					tmpNode.x = i;
					tmpNode.y = j;
					tmpNode.index = i * width + j;
					tmpNode.step = 0;
					bfs(tmpNode);

				}
			}
		}
		// 初始化@到S的最短距离
		for (int i = 1; i < checkPointsNum + 2; i++) {
			f[i][0] = shortestDistance[i][0];
		}
	}

	/**
	 * 打印最短路径信息
	 * 
	 * @created Oct 29, 2014
	 * @author  chenshanfu
	 */
	public static void print() {
		for (int i = 0; i < checkPointsNum + 2; i++) {
			for (int j = 0; j < checkPointsNum + 2; j++) {
				System.out.print(shortestDistance[i][j] + " ");
			}
			System.out.println();
		}
	}

	/**
	 * 状态压缩DP,求解到第k个点并且经过state状态的最优解,同时记录中间递归结果,加速搜索进度
	 * 
	 * @param k
	 * @param state
	 * @return
	 * @created Oct 29, 2014
	 * @author  chenshanfu
	 */
	public static int solve(int k, int state) {
		// System.out.println("k="+k+" state:"+state);
		if (f[k][state] > 0 && f[k][state] < Integer.MAX_VALUE)
			return f[k][state];
		else {
			int ans = Integer.MAX_VALUE;
			for (int i = 1; i < checkPointsNum + 2; i++) {
				if ((state & (int) Math.pow(2.0, 1.0 * (i - 1))) != 0) {
					int subsolve = solve(i,
							state ^ (int) Math.pow(2.0, 1.0 * (i - 1)));//最好用(1 << (i - 1)))位运算来实现,方便快捷
					if (shortestDistance[i][k] != Integer.MAX_VALUE
							&& subsolve != Integer.MAX_VALUE) {
						int sub = subsolve + shortestDistance[i][k];
						if (sub < ans) {
							ans = sub;
						}
					}
				}
			}
			f[k][state] = ans;
			return ans;
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		init();
		if (isException) {
			System.out.println("-1");
		} else {
			getMinDistance();
			// print();
			if (isException
					|| shortestDistance[0][checkPointsNum + 1] == Integer.MAX_VALUE) {
				System.out.println("-1");
			} else {
				int ans = solve(checkPointsNum + 1,
						(int) Math.pow(2.0, 1.0 * checkPointsNum) - 1);
				if (ans == Integer.MAX_VALUE)
					System.out.println("-1");
				else
					System.out.println(ans);
			}
		}
	}
}


testData:

8 6
########
#@....G#
##.##@##
#..@..S#
#@.....#
########
18

8 6
########
#@....G#
########
#..@..S#
#@.....#
########
-1

5 4
#####
#...#
#S#G#
#####
4

5 5
#####
#.@@#
#S###
#..G#
#####
9

5 5
#####
#S..#
##G##
#..@#
#####
6

5 5
####@
#.@@#
#S###
#..G#
#####
-1

8 6
########
#@.S..G#
#####@##
#..##...
#@....@#
########
23

8 6
########
#@....G#
#####@##
#..S#...
#@....@#
########
21

8 6
########
#S.S..G#
#####@##
#..##...
#@....@#
########
-1

8 6
########
#@.S..G#
########
#..##...
#@....@#
########
-1

8 6
########
#@.S..G.
#######.
#..##...
#@....@#
########
27

8 6
########
#@.S..G.
#.#####.
#..##...
#@....@#
########
15



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值