小青蛙用仅剩的体力值P走地下迷宫。迷宫为一个n*m的grid,每个位置为0或1,1代表可以走,0代表无法走。初始节点为(0,0),目的节点为(0,m - 1)(保证初始和目的都为1)。青蛙往上走时消耗体力值3,水平走消耗1,往下走不消耗体力值。计算青蛙能否用体力值P跳出迷宫。若不能跳出,输出“can not escape”,否则输出路径。
输入顺序为n,m,p,接着n行m列是gird里的数。
示例:
4 4 10
1 0 0 1
1 1 0 1
0 1 1 1
0 0 1 1
输出:
【0,0】,【1,0】,【1,1】,【2,1】,【2,2】【2,3】【1,3】【0,3】
不知道别人咋做的(感觉自己做的好复杂 = =),看到这题想起了曾做过的“积水的城市”,用的SPFA,就是把每个节点a的邻接节点保存在该节点的List<Vertex> adjacience中,每个邻接节点都有一个p值,代表从a走到每个邻接点需要消耗的体力值。然后通过遍历,计算从源节点出发到每个节点的最小消耗体力值minp,用v[i][j].minp表示。最后判断目的节点的minp是否小于等于p,若是,则输出。
输出的时候,用到了遍历时加的last(last也是一个节点)。当某节点改变minp,则它的上一个节点last,必然是导致这个最小minp的上一节点,也必然是路径的上一节点。最后从目的节点倒序输出即可。
class Vertex {
int a; //节点的横坐标
int b; // 纵坐标
int p = 0;// 每个节点通过adjacience到达邻节点需要消耗p
List<Vertex> adjacience; //邻节点
boolean isInQueue;
int minp = Integer.MAX_VALUE / 2;
Vertex last; // 前一个节点
public Vertex(int i ,int j,int p) {
this.a = i;
this.b = j;
this.p += p;
this.isInQueue = false;
this.adjacience = new ArrayList<Vertex>();
}
}
public class Main {
static int n;
static int m;
static int p;
static int[][] grid;
static Vertex[][] v;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
p = in.nextInt();
grid = new int[n][m];
for (int i = 0; i< n; i++) {
for(int j = 0; j< m; j++) {
grid[i][j] = in.nextInt();
}
}
if (minP(grid) > p) System.out.println("can not escape !");
else print_ans(v[0][m - 1]);
in.close();
}
public static int minP(int[][] a) {
v = new Vertex[n][m];
for (int i = 0; i< n; i++) {
for(int j = 0; j< m; j++) {
if (a[i][j] == 1) {
v[i][j] = new Vertex(i, j, 0);
if (i > 0 && a[i - 1][j] == 1) {
v[i][j].adjacience.add(new Vertex(i - 1, j, 3)); // 往上走,消耗体力3
}
if (j > 0 && a[i][j - 1] == 1) {
v[i][j].adjacience.add(new Vertex(i, j - 1, 1)); // 往左走
}
if (i < n - 1 && a[i + 1][j] == 1) {
v[i][j].adjacience.add(new Vertex(i + 1, j, 0)); //往下
}
if (j < m - 1 && a[i][j + 1] == 1) {
v[i][j].adjacience.add(new Vertex(i, j + 1, 1)); //往右
}
}
}
}
Queue<Vertex> queue = new LinkedList<Vertex>();
v[0][0].minp = 0;
queue.add(v[0][0]);
v[0][0].isInQueue = true;
Vertex former = null; // former保证了路径不走回头路,比如a节点的邻节点为b,遍历b的邻节点时要排除掉a点
while(!queue.isEmpty()) {
Vertex s = queue.poll();
s.isInQueue = false;
for (int i = 0; i < v[s.a][s.b].adjacience.size(); i++) {
Vertex b = v[s.a][s.b].adjacience.get(i);
if(former == null || (b.a != former.a || b.b != former.b)) {
if (v[b.a][b.b].minp > v[s.a][s.b].minp + b.p) { // 注意此处必须为b.p,因为v[i][j]的p为0
v[b.a][b.b].minp = v[s.a][s.b].minp + b.p;
v[b.a][b.b].last = v[s.a][s.b];
if(!b.isInQueue) {
b.isInQueue = true;
queue.add(b);
}
}
}
former= s;
}
}
return v[0][m - 1].minp;
}
// 打印结果
public static void print_ans(Vertex v) {
boolean s = true;
List<Integer[]> re = new ArrayList<Integer[]>();
while (s) {
Integer[] result = new Integer[2];
result[0] = v.a;
re.add(result);
result[1] = v.b;
if (v.a == 0 && v.b == 0)
s = false;
v = v.last;
}
for (int i = re.size() - 1; i > 0; i--) {
System.out.print("[" + re.get(i)[0] + "," + re.get(i)[1] + "]" + ",");
}
System.out.println("[" + re.get(0)[0] + "," + re.get(0)[1] + "]");
}
}