仙岛求药 最短路做法

仙岛求药 Dijkstra算法

题目描述

少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由M×N个方格组成,有的方格内有可以瞬秒李逍遥的怪物,而有的方格内则是安全。现在李逍遥想尽快找到仙药,显然他应避开有怪物的方格,并经过最少的方格,而且那里会有神秘人物等待着他。现在要求你来帮助他实现这个目标。 下图 显示了一个迷阵的样例及李逍遥找到仙药的路线。
在这里插入图片描述

输入格式

输入有多组测试数据. 每组测试数据以两个非零整数 M 和 N 开始,两者均不大于20。M 表示迷阵行数, N 表示迷阵列数。接下来有 M 行, 每行包含N个字符,不同字符分别代表不同含义:

  1. ‘@’:少年李逍遥所在的位置;

  2. ‘.’:可以安全通行的方格;

  3. ‘#’:有怪物的方格;

  4. ‘*’:仙药所在位置。

当在一行中读入的是两个零时,表示输入结束。

输出格式

对于每组测试数据,分别输出一行,该行包含李逍遥找到仙药需要穿过的最少的方格数目(计数包括初始位置的方块)。如果他不可能找到仙药, 则输出 -1。

样例

样例输入

8 8
.@##…#
#…#.#
#.#.##…
…#.###.
#.#…#.
…###.#.
…#.
.#…###
6 5
.
.#.
.#…
…##.

.#…
…@
9 6
.#…#.
.#.*.#
.####.
…#…
…#…
…#…
…#…
#.@.##
.#…#.
0 0

样例输出

10
8
-1

分析

首先正常人看到这道一定会想到用BFS,但我们要尝试阴间算法,我们不是正常人……

最短路

我们把这张n * m的地图看成n * m个点。不难发现,只要两个点之间可以以一步的距离走到,就可以连成一条线。那么再把这些点的最短步数即最短路算出来就行了。起点就是@(李逍遥的位置),重点就为*(仙药)。

初始化

首先读入这些点,再把这些点连接起来
假设这个点为n,m,则用hash(勉强算是吧)的思想把这个点记为M * (n - 1) + m,即可,方便后面访问该节点。

char A;
for(int i = 1; i <= N; i++) {
    
    
	for(int j = 1; j <= M; j++) {
    
    
		cin >> A;
		if(A == '.')
			mp[i][j] = 1;
		else if(A == '#')
			mp[i][j] = 2;
		else if(A == '@') {
    
    
			mp[i][j] = 3;
			c1 = i; c2 = j;
		}
		else {
    
    
			mp[i][j] = 4;
			t1 = i; t2 = j;
		}
	}
}
c = M * (c1 - 1) + c2;
t = M * (t1 - 1) + t2;
for(int i = 1; i <= N; i++) {
    
    
	for(int j = 1; j <= M; j++) {
    
    
		int A = M * (i - 1) + j, B;
		if(mp[i][j] == 0 || mp[i][j] == 2)
			continue;
		for(int k = 1; k <= 4; k++) {
    
    
			int X = i + x[k], Y = j + y[k];
			if(mp[X][Y] >= 1 && mp[X][Y] != 2) {
    
    
				B = M * (X - 1) + Y;
				a[A].push_back(Node(B, 1));
				a[B].push_back(Node(A, 1));
			}
		}
	}
}

核心代码

虽是核心代码,但是就是一个Dijkstra板子。
(不会吧不会吧,不会真的有人不会Dijkstra吧,不会真的有人用Floyed吧,这都什么年代了)

void Dijkstra() {
    
    
	q.push(Node(c, 0));
	memset(d, 0x3f, sizeof(d));
	d[c] = 0;
	while(!q.empty()) {
    
    
		Node now = q.top();
		q.pop();
		int i = now.v;
		if(f[i]) continue;
		f[i] = 1;
		int SIZ = a[i].size();
		for(int j = 0; j < SIZ; j++) {
    
    
			if(d[a[i][j].v] > d[i] + a[i][j].m) {
    
    
				d[a[i][j].v] = d[i] + a[i][j].m;
				q.push(Node(a[i][j].v, d[a[i][j].v]));
			}
		}
	}
	if(d[t] == 0x3f3f3f3f)
		printf("-1\n");
	else
		printf("%d\n", d[t]);
}

代码

综上所述,代码就出来了……

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 1e3 + 5;
struct Node {
    
    
	int v, m;
	Node() {
    
    }
	Node(int V, int M) {
    
    
		v = V;
		m = M;
	}
	friend bool operator < (Node x, Node y) {
    
    
		return x.m > y.m;
	}
};
priority_queue<Node> q;
vector<Node> a[MAXN];
int mp[MAXN][MAXN];
int x[MAXN] = {
    
    0, -1, 1, 0, 0};
int y[MAXN] = {
    
    0, 0, 0, -1, 1};
int d[MAXN];
bool f[MAXN];
int N, M, n, m, c, t;
int c1, c2, t1, t2;
void Init() {
    
    
	c1 = c2 = t1 = t2 = n = m = c = t = 0;
	memset(d, 0, sizeof(d));
	memset(f, 0, sizeof(f));
	memset(mp, 0, sizeof(mp));
	while(!q.empty())
		q.pop();
	for(int i = 0; i < MAXN; i++)
		a[i].clear();
}
void Read() {
    
    
	char A;
	for(int i = 1; i <= N; i++) {
    
    
		for(int j = 1; j <= M; j++) {
    
    
			cin >> A;
			if(A == '.')
				mp[i][j] = 1;
			else if(A == '#')
				mp[i][j] = 2;
			else if(A == '@') {
    
    
				mp[i][j] = 3;
				c1 = i; c2 = j;
			}
			else {
    
    
				mp[i][j] = 4;
				t1 = i; t2 = j;
			}
		}
	}
	c = M * (c1 - 1) + c2;
	t = M * (t1 - 1) + t2;
	for(int i = 1; i <= N; i++) {
    
    
		for(int j = 1; j <= M; j++) {
    
    
			int A = M * (i - 1) + j, B;
			if(mp[i][j] == 0 || mp[i][j] == 2)
				continue;
			for(int k = 1; k <= 4; k++) {
    
    
				int X = i + x[k], Y = j + y[k];
				if(mp[X][Y] >= 1 && mp[X][Y] != 2) {
    
    
					B = M * (X - 1) + Y;
					a[A].push_back(Node(B, 1));
					a[B].push_back(Node(A, 1));
				}
			}
		}
	}
	q.push(Node(c, 0));
}
void Dijkstra() {
    
    
	memset(d, 0x3f, sizeof(d));
	d[c] = 0;
	while(!q.empty()) {
    
    
		Node now = q.top();
		q.pop();
		int i = now.v;
		if(f[i]) continue;
		f[i] = 1;
		int SIZ = a[i].size();
		for(int j = 0; j < SIZ; j++) {
    
    
			if(d[a[i][j].v] > d[i] + a[i][j].m) {
    
    
				d[a[i][j].v] = d[i] + a[i][j].m;
				q.push(Node(a[i][j].v, d[a[i][j].v]));
			}
		}
	}
	if(d[t] == 0x3f3f3f3f)
		printf("-1\n");
	else
		printf("%d\n", d[t]);
}
int main() {
    
    
	while(scanf("%d %d", &N, &M) != EOF && N && M) {
    
    
		Init();
		Read();
		Dijkstra();
	}
	return 0;
}

这个算法时间复杂度为 O ( n ∗ m ∗ l o g ( n ∗ m ) ) O(n*m*log(n*m)) O(nmlog(nm)),比那啥bfs说不定就快多了。
这就是阴间的代码吗,i了i了

猜你喜欢

转载自blog.csdn.net/Face_the_Blast/article/details/108857810