题目链接 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;
}
}
}