ACM ZOJ 1649 (Rescue)

本文介绍了使用不同寻路算法解决迷宫问题的方法,包括宽度优先搜索(BFS)、迪杰斯特拉(Dijkstra)、贝尔曼-福特(Bellman-Ford)及SPFA算法。通过实例演示了每种算法的应用场景及其优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1649

思路一 广度优先搜索,用优先队列实现,从a开始,当遇到r时就停止搜索

思路二 转换成最短路问题,先用一个矩阵存储matrix输入的字符,然后遍历矩阵,找到两个相邻的点:如果两个点中有#,则距离为INF;如果有且仅有1个x,则距离为1.5;如果有两个x,则距离为2;其它情况,距离为1。建立一个超级终点,求a到超级终点的距离。

程序一 宽度优先搜索

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = Integer.parseInt(scn.next());
			Search search = new Search(height, width);
			for (int i = 0; i < height; ++i) {
				String str = scn.next();
				search.setMatrixLine(i, str.toCharArray());
				int position = str.indexOf("a");
				if (-1 != position) {
					search.setStartX(i);
					search.setStartY(position);
				}
			}
			search.beginSearch();
		}
		scn.close();
	}

}

class Search {

	private final int[][] direction = { { -1, 0 }, { 1, 0 }, { 0, -1 },
			{ 0, 1 } };
	private int height;
	private int width;
	private char[][] matrix;
	private int startX;
	private int startY;

	public Search(int height, int width) {
		this.height = height;
		this.width = width;
		matrix = new char[height][width];
	}

	public void beginSearch() {
		Queue<Node> queue = new PriorityQueue<Node>();
		queue.offer(new Node(startX, startY, 0));
		matrix[startX][startY] = '#';
		while (!queue.isEmpty()) {
			Node node = queue.poll();
			for (int k = 0; k < 4; ++k) {
				int nextX = node.getX() + direction[k][0];
				int nextY = node.getY() + direction[k][1];
				int nextTime = node.getTime() + 1;
				Node tmp = new Node(nextX, nextY, nextTime);
				if (0 > nextX || nextX >= height || 0 > nextY || nextY >= width
						|| '#' == matrix[nextX][nextY]) {
					continue;
				}
				if ('r' == matrix[nextX][nextY]) {
					System.out.println(nextTime);
					return;
				} else if ('x' == matrix[nextX][nextY]) {
					tmp.setTime(nextTime + 1);
				}
				queue.offer(tmp);
				matrix[nextX][nextY] = '#';
			}
		}
		System.out.println("Poor ANGEL has to stay in the prison all his life.");
	}

	public void setMatrixLine(int line, char[] ch) {
		matrix[line] = ch;
	}

	public void setStartX(int startX) {
		this.startX = startX;
	}

	public void setStartY(int startY) {
		this.startY = startY;
	}

}

class Node implements Comparable<Node> {

	private int x;
	private int y;
	private int time;

	public Node(int x, int y, int time) {
		this.x = x;
		this.y = y;
		this.time = time;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}

	public int getTime() {
		return time;
	}

	public void setTime(int time) {
		this.time = time;
	}

	@Override
	public int compareTo(Node node) {
		if (this.time != node.time) {
			return this.time - node.time;
		} else if (this.x != node.x) {
			return this.x - node.x;
		} else {
			return this.y - node.y;
		}
	}

}

程序二 dijkstra 优先队列优化算法

import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = Integer.parseInt(scn.next());
			int pointsNumber = height * width + 2;
			int edgesNumber = 5 * width * height - 2 * (height + width);
			char[][] matrix = new char[height][width];
			for (int i = 0; i < height; i++) {
				matrix[i] = scn.next().toCharArray();
			}
			Dijkstra dijkstra = new Dijkstra(pointsNumber, edgesNumber);
			int initStart = -1;
			int initEnd = height * width + 1;
			for (int i = 0; i < height - 1; ++i) {
				for (int j = 0; j < width - 1; ++j) {
					int start = i * width + j + 1;
					int end = i * width + j + 1 + 1;
					if ('#' != matrix[i][j] && '#' != matrix[i][j + 1]) {
						double distance = 1;
						if ('x' == matrix[i][j]) {
							distance += 0.5;
						}
						if ('x' == matrix[i][j + 1]) {
							distance += 0.5;
						}
						dijkstra.addEdge(start, end, distance);
						dijkstra.addEdge(end, start, distance);
					}
					end = (i + 1) * width + j + 1;
					if ('#' != matrix[i][j] && '#' != matrix[i + 1][j]) {
						double distance = 1;
						if ('x' == matrix[i][j]) {
							distance += 0.5;
						}
						if ('x' == matrix[i + 1][j]) {
							distance += 0.5;
						}
						dijkstra.addEdge(start, end, distance);
						dijkstra.addEdge(end, start, distance);
					}
					if ('a' == matrix[i][j]) {
						initStart = i * width + j + 1;
					}
					if ('r' == matrix[i][j]) {
						dijkstra.addEdge(i * width + j + 1, initEnd, 0);
					}
				}
			}
			for (int i = height - 1, j = 0; j < width - 1; ++j) {
				int start = i * width + j + 1;
				int end = i * width + j + 1 + 1;
				if ('#' != matrix[i][j] && '#' != matrix[i][j + 1]) {
					double distance = 1;
					if ('x' == matrix[i][j]) {
						distance += 0.5;
					}
					if ('x' == matrix[i][j + 1]) {
						distance += 0.5;
					}
					dijkstra.addEdge(start, end, distance);
					dijkstra.addEdge(end, start, distance);
				}
				if ('a' == matrix[i][j]) {
					initStart = i * width + j + 1;
				}
				if ('r' == matrix[i][j]) {
					dijkstra.addEdge(i * width + j + 1, initEnd, 0);
				}
			}
			for (int j = width - 1, i = 0; i < height - 1; ++i) {
				int start = i * width + j + 1;
				int end = (i + 1) * width + j + 1;
				if ('#' != matrix[i][j] && '#' != matrix[i + 1][j]) {
					double distance = 1;
					if ('x' == matrix[i][j]) {
						distance += 0.5;
					}
					if ('x' == matrix[i + 1][j]) {
						distance += 0.5;
					}
					dijkstra.addEdge(start, end, distance);
					dijkstra.addEdge(end, start, distance);
				}
				if ('a' == matrix[i][j]) {
					initStart = i * width + j + 1;
				}
				if ('r' == matrix[i][j]) {
					dijkstra.addEdge(i * width + j + 1, initEnd, 0);
				}
			}
			if ('a' == matrix[height - 1][width - 1]) {
				initStart = height * width;
			}
			if ('r' == matrix[height - 1][width - 1]) {
				dijkstra.addEdge(height * width, initEnd, 0);
			}
			double distance = dijkstra.calculateDistance(initStart, initEnd);
			if (dijkstra.hasMinDistance()) {
				System.out.println(String.format("%.0f", distance));
			} else {
				System.out.println("Poor ANGEL has to stay in the prison all his life.");
			}
		}
		scn.close();
	}

}

class Dijkstra {

	private final double INF = Double.MAX_VALUE / 2;
	private int pointsNumber;
	private int edgesNumber;
	private double[] edgesDistance;
	private int[] edgesEnd;
	private int[] nextStart;
	private int[] startMax;
	private boolean[] visit;
	private double[] resultDistance;
	private int[] prePoint;
	private double resultMinDistance;

	public Dijkstra(int pointsNumber, int edgesNumber) {
		this.pointsNumber = pointsNumber;
		this.edgesNumber = 0;
		edgesDistance = new double[edgesNumber];
		edgesEnd = new int[edgesNumber];
		nextStart = new int[edgesNumber];
		startMax = new int[pointsNumber];
		Arrays.fill(startMax, -1);
		visit = new boolean[pointsNumber];
		resultDistance = new double[pointsNumber];
		prePoint = new int[pointsNumber];
		resultMinDistance = INF;
	}

	public void addEdge(int start, int end, double distance) {
		edgesDistance[edgesNumber] = distance;
		edgesEnd[edgesNumber] = end;
		nextStart[edgesNumber] = startMax[start];
		startMax[start] = edgesNumber++;
	}

	public double calculateDistance(int initStart, int initEnd) {
		Arrays.fill(visit, false);
		Arrays.fill(resultDistance, INF);
		Arrays.fill(prePoint, -1);
		visit[initStart] = true;
		resultDistance[initStart] = 0;
		int currentPoint = initStart;
		Queue<Node> queue = new PriorityQueue<Node>();
		for (int i = 1; i < pointsNumber; ++i) {
			for (int j = startMax[currentPoint]; j != -1; j = nextStart[j]) {
				int k = edgesEnd[j];
				if (!visit[k]
						&& resultDistance[currentPoint] < resultDistance[k]
								- edgesDistance[j]) {
					resultDistance[k] = resultDistance[currentPoint]
							+ edgesDistance[j];
					queue.offer(new Node(k, resultDistance[k]));
					prePoint[k] = currentPoint;
				}
			}
			while (!queue.isEmpty()) {
				Node tmp = queue.peek();
				if (visit[tmp.getPoint()]) {
					queue.poll();
				} else {
					break;
				}
			}
			if (queue.isEmpty()) {
				break;
			}
			currentPoint = queue.poll().getPoint();
			visit[currentPoint] = true;
			if (currentPoint == initEnd) {
				break;
			}
		}
		resultMinDistance = resultDistance[initEnd];
		return resultDistance[initEnd];
	}

	public boolean hasMinDistance() {
		if (INF <= resultMinDistance) {
			return false;
		} else {
			return true;
		}
	}

}

class Node implements Comparable<Node> {

	private int point;
	private double distance;

	public Node(int point, double distance) {
		this.point = point;
		this.distance = distance;
	}

	public int getPoint() {
		return point;
	}

	public double getDistance() {
		return distance;
	}

	@Override
	public int compareTo(Node qnode) {
		if (this.distance > qnode.distance) {
			return 1;
		} else if (this.distance < qnode.distance) {
			return -1;
		} else {
			return this.point - qnode.point;
		}
	}

}

程序三 bellman-ford 算法

import java.util.Arrays;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = Integer.parseInt(scn.next());
			int pointsNumber = height * width + 2;
			int edgesNumber = 5 * width * height - 2 * (height + width);
			char[][] matrix = new char[height][width];
			for (int i = 0; i < height; i++) {
				matrix[i] = scn.next().toCharArray();
			}
			BellmanFord bellmanFord = new BellmanFord(pointsNumber, edgesNumber);
			int initStart = -1;
			int initEnd = height * width + 1;
			for (int i = 0; i < height - 1; ++i) {
				for (int j = 0; j < width - 1; ++j) {
					int start = i * width + j + 1;
					int end = i * width + j + 1 + 1;
					if ('#' != matrix[i][j] && '#' != matrix[i][j + 1]) {
						double distance = 1;
						if ('x' == matrix[i][j]) {
							distance += 0.5;
						}
						if ('x' == matrix[i][j + 1]) {
							distance += 0.5;
						}
						bellmanFord.addEdge(start, end, distance);
						bellmanFord.addEdge(end, start, distance);
					}
					end = (i + 1) * width + j + 1;
					if ('#' != matrix[i][j] && '#' != matrix[i + 1][j]) {
						double distance = 1;
						if ('x' == matrix[i][j]) {
							distance += 0.5;
						}
						if ('x' == matrix[i + 1][j]) {
							distance += 0.5;
						}
						bellmanFord.addEdge(start, end, distance);
						bellmanFord.addEdge(end, start, distance);
					}
					if ('a' == matrix[i][j]) {
						initStart = i * width + j + 1;
					}
					if ('r' == matrix[i][j]) {
						bellmanFord.addEdge(i * width + j + 1, initEnd, 0);
					}
				}
			}
			for (int i = height - 1, j = 0; j < width - 1; ++j) {
				int start = i * width + j + 1;
				int end = i * width + j + 1 + 1;
				if ('#' != matrix[i][j] && '#' != matrix[i][j + 1]) {
					double distance = 1;
					if ('x' == matrix[i][j]) {
						distance += 0.5;
					}
					if ('x' == matrix[i][j + 1]) {
						distance += 0.5;
					}
					bellmanFord.addEdge(start, end, distance);
					bellmanFord.addEdge(end, start, distance);
				}
				if ('a' == matrix[i][j]) {
					initStart = i * width + j + 1;
				}
				if ('r' == matrix[i][j]) {
					bellmanFord.addEdge(i * width + j + 1, initEnd, 0);
				}
			}
			for (int j = width - 1, i = 0; i < height - 1; ++i) {
				int start = i * width + j + 1;
				int end = (i + 1) * width + j + 1;
				if ('#' != matrix[i][j] && '#' != matrix[i + 1][j]) {
					double distance = 1;
					if ('x' == matrix[i][j]) {
						distance += 0.5;
					}
					if ('x' == matrix[i + 1][j]) {
						distance += 0.5;
					}
					bellmanFord.addEdge(start, end, distance);
					bellmanFord.addEdge(end, start, distance);
				}
				if ('a' == matrix[i][j]) {
					initStart = i * width + j + 1;
				}
				if ('r' == matrix[i][j]) {
					bellmanFord.addEdge(i * width + j + 1, initEnd, 0);
				}
			}
			if ('a' == matrix[height - 1][width - 1]) {
				initStart = height * width;
			}
			if ('r' == matrix[height - 1][width - 1]) {
				bellmanFord.addEdge(height * width, initEnd, 0);
			}
			double distance = bellmanFord.calculateDistance(initStart, initEnd);
			if (bellmanFord.hasMinDistance()) {
				System.out.println(String.format("%.0f", distance));
			} else {
				System.out.println("Poor ANGEL has to stay in the prison all his life.");
			}
		}
		scn.close();
	}

}

class BellmanFord {

	private final double INF = Double.MAX_VALUE / 2;
	private int pointsNumber;
	private int edgesNumber;
	private Edge[] edge;
	private double[] resultDistance;
	private int[] prePoint;
	private double resultMinDistance;

	private boolean relax(int start, int end, double distance) {
		if (resultDistance[end] - distance > resultDistance[start]) {
			resultDistance[end] = resultDistance[start] + distance;
			prePoint[end] = start;
			return true;
		} else {
			return false;
		}
	}

	public BellmanFord(int pointsNumber, int edgesNumber) {
		this.pointsNumber = pointsNumber;
		this.edgesNumber = 0;
		edge = new Edge[edgesNumber];
		resultDistance = new double[pointsNumber];
		prePoint = new int[pointsNumber];
		resultMinDistance = INF;
	}

	public void addEdge(int start, int end, double distance) {
		edge[edgesNumber++] = new Edge(start, end, distance);
	}

	public double calculateDistance(int initStart, int initEnd) {
		Arrays.fill(resultDistance, INF);
		Arrays.fill(prePoint, -1);
		resultDistance[initStart] = 0;
		for (int i = 1; i < pointsNumber; ++i) {
			Boolean flag = false;
			for (int j = 0; j < edgesNumber; ++j) {
				if (relax(edge[j].getStart(), edge[j].getEnd(),
						edge[j].getDistance())) {
					flag = true;
				}
			}
			if (!flag) {
				break;
			}
		}
		for (int i = 0; i < edgesNumber; ++i) {
			if (relax(edge[i].getStart(), edge[i].getEnd(),
					edge[i].getDistance())) {
				resultMinDistance = -INF;
				return -INF;
			}
		}
		resultMinDistance = resultDistance[initEnd];
		return resultDistance[initEnd];
	}

	public boolean hasMinDistance() {
		if (hasNegativeRing() || INF <= resultMinDistance) {
			return false;
		} else {
			return true;
		}
	}

	public boolean hasNegativeRing() {
		if (-INF >= resultMinDistance) {
			return true;
		} else {
			return false;
		}
	}

}

class Edge {

	private int start;
	private int end;
	private double distance;

	public Edge(int start, int end, double distance) {
		this.start = start;
		this.end = end;
		this.distance = distance;
	}

	public int getStart() {
		return start;
	}

	public int getEnd() {
		return end;
	}

	public double getDistance() {
		return distance;
	}

}

程序四 spfa 算法

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = Integer.parseInt(scn.next());
			int pointsNumber = height * width + 2;
			int edgesNumber = 5 * width * height - 2 * (height + width);
			char[][] matrix = new char[height][width];
			for (int i = 0; i < height; i++) {
				matrix[i] = scn.next().toCharArray();
			}
			Spfa spfa = new Spfa(pointsNumber, edgesNumber);
			int initStart = -1;
			int initEnd = height * width + 1;
			for (int i = 0; i < height - 1; ++i) {
				for (int j = 0; j < width - 1; ++j) {
					int start = i * width + j + 1;
					int end = i * width + j + 1 + 1;
					if ('#' != matrix[i][j] && '#' != matrix[i][j + 1]) {
						double distance = 1;
						if ('x' == matrix[i][j]) {
							distance += 0.5;
						}
						if ('x' == matrix[i][j + 1]) {
							distance += 0.5;
						}
						spfa.addEdge(start, end, distance);
						spfa.addEdge(end, start, distance);
					}
					end = (i + 1) * width + j + 1;
					if ('#' != matrix[i][j] && '#' != matrix[i + 1][j]) {
						double distance = 1;
						if ('x' == matrix[i][j]) {
							distance += 0.5;
						}
						if ('x' == matrix[i + 1][j]) {
							distance += 0.5;
						}
						spfa.addEdge(start, end, distance);
						spfa.addEdge(end, start, distance);
					}
					if ('a' == matrix[i][j]) {
						initStart = i * width + j + 1;
					}
					if ('r' == matrix[i][j]) {
						spfa.addEdge(i * width + j + 1, initEnd, 0);
					}
				}
			}
			for (int i = height - 1, j = 0; j < width - 1; ++j) {
				int start = i * width + j + 1;
				int end = i * width + j + 1 + 1;
				if ('#' != matrix[i][j] && '#' != matrix[i][j + 1]) {
					double distance = 1;
					if ('x' == matrix[i][j]) {
						distance += 0.5;
					}
					if ('x' == matrix[i][j + 1]) {
						distance += 0.5;
					}
					spfa.addEdge(start, end, distance);
					spfa.addEdge(end, start, distance);
				}
				if ('a' == matrix[i][j]) {
					initStart = i * width + j + 1;
				}
				if ('r' == matrix[i][j]) {
					spfa.addEdge(i * width + j + 1, initEnd, 0);
				}
			}
			for (int j = width - 1, i = 0; i < height - 1; ++i) {
				int start = i * width + j + 1;
				int end = (i + 1) * width + j + 1;
				if ('#' != matrix[i][j] && '#' != matrix[i + 1][j]) {
					double distance = 1;
					if ('x' == matrix[i][j]) {
						distance += 0.5;
					}
					if ('x' == matrix[i + 1][j]) {
						distance += 0.5;
					}
					spfa.addEdge(start, end, distance);
					spfa.addEdge(end, start, distance);
				}
				if ('a' == matrix[i][j]) {
					initStart = i * width + j + 1;
				}
				if ('r' == matrix[i][j]) {
					spfa.addEdge(i * width + j + 1, initEnd, 0);
				}
			}
			if ('a' == matrix[height - 1][width - 1]) {
				initStart = height * width;
			}
			if ('r' == matrix[height - 1][width - 1]) {
				spfa.addEdge(height * width, initEnd, 0);
			}
			double distance = spfa.calculateDistance(initStart, initEnd);
			if (spfa.hasMinDistance()) {
				System.out.println(String.format("%.0f", distance));
			} else {
				System.out.println("Poor ANGEL has to stay in the prison all his life.");
			}
		}
		scn.close();
	}

}

class Spfa {

	private final double INF = Double.MAX_VALUE / 2;
	private int pointsNumber;
	private int edgesNumber;
	private double[] edgesDistance;
	private int[] edgesEnd;
	private int[] nextStart;
	private int[] startMax;
	private boolean[] visit;
	private double[] resultDistance;
	private int[] prePoint;
	private int[] count;
	private double resultMinDistance;

	private boolean relax(int start, int end, double distance) {
		if (resultDistance[end] - distance > resultDistance[start]) {
			resultDistance[end] = resultDistance[start] + distance;
			prePoint[end] = start;
			return true;
		} else {
			return false;
		}
	}

	public Spfa(int pointsNumber, int edgesNumber) {
		this.pointsNumber = pointsNumber;
		this.edgesNumber = 0;
		edgesDistance = new double[edgesNumber];
		edgesEnd = new int[edgesNumber];
		nextStart = new int[edgesNumber];
		startMax = new int[pointsNumber];
		Arrays.fill(startMax, -1);
		visit = new boolean[pointsNumber];
		resultDistance = new double[pointsNumber];
		prePoint = new int[pointsNumber];
		count = new int[pointsNumber];
		resultMinDistance = INF;
	}

	public void addEdge(int start, int end, double distance) {
		edgesDistance[edgesNumber] = distance;
		edgesEnd[edgesNumber] = end;
		nextStart[edgesNumber] = startMax[start];
		startMax[start] = edgesNumber++;
	}

	public double calculateDistance(int initStart, int initEnd) {
		Arrays.fill(visit, false);
		Arrays.fill(resultDistance, INF);
		Arrays.fill(prePoint, -1);
		Arrays.fill(count, 0);
		visit[initStart] = true;
		resultDistance[initStart] = 0;
		++count[initStart];
		Queue<Integer> queue = new LinkedList<Integer>();
		queue.offer(initStart);
		while (!queue.isEmpty()) {
			int start = queue.poll();
			visit[start] = false;
			for (int i = startMax[start]; i != -1; i = nextStart[i]) {
				int end = edgesEnd[i];
				if (relax(start, end, edgesDistance[i]) && !visit[end]) {
					queue.offer(end);
					visit[end] = true;
					if ((++count[end]) > pointsNumber) {
						resultMinDistance = -INF;
						return -INF;
					}
				}
			}
		}
		resultMinDistance = resultDistance[initEnd];
		return resultDistance[initEnd];
	}

	public boolean hasMinDistance() {
		if (hasNegativeRing() || INF <= resultMinDistance) {
			return false;
		} else {
			return true;
		}
	}

	public boolean hasNegativeRing() {
		if (-INF >= resultMinDistance) {
			return true;
		} else {
			return false;
		}
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值