1.题目描述:点击打开链接
2.解题思路:这道题是稀疏图存储+BFS,只要存储好稀疏图,本题就不难解决,但还是怪自己太年幼,不会写稀疏图,磕磕绊绊自己敲了一天样例还有一个没过==,最后弃疗直接学习大牛们的代码。有很多值得学习的地方,关键位置都标记了注释。
3.代码:
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define MAXN 16 #define MAXM 192 int getnum(int a, int b, int c) { return (a << 16) | (b << 8) | c;//编码 } int ok(int a, int b, int a1, int b1) { return ((a1 == b1) || (a1 == b && b1 == a));//两种非法情况,第一种:两个鬼下一步走到了同一结点 //第二种:两个鬼在一步之内交换位置 } int cx[] = { -1, 1, 0, 0, 0 }; int cy[] = { 0, 0, -1, 1, 0 }; int id[MAXN + 10][MAXN + 10]; int G[MAXM + 10][5];//由于相邻结点最多有5个(包含自身),因此最后一个值是5 int st[3], ed[3];//st存放起始位置,ed存放目标位置 int edge[MAXM + 10], d[MAXM + 10][MAXM + 10][MAXM + 10]; int w, h, n, cnt; char M[MAXN + 10][MAXN + 10];//原地图 void bfs() { queue <int> q; memset(d, -1, sizeof(d)); q.push(getnum(st[0], st[1], st[2])); d[st[0]][st[1]][st[2]] = 0; while (!q.empty()) { int u = q.front(); q.pop(); int a = (u >> 16) & 255, b = (u >> 8) & 255, c = u & 255;//解码各个鬼的位置 if (a == ed[0] && b == ed[1] && c == ed[2]) return; //找到了目标状态 for (int i = 1; i <= edge[a]; i++) { int a1 = G[a][i]; for (int j = 1; j <= edge[b]; j++) { int b1 = G[b][j]; if (ok(a, b, a1, b1)) continue; for (int k = 1; k <= edge[c]; k++) { int c1 = G[c][k]; if (ok(a, c, a1, c1)) continue; if (ok(b, c, b1, c1)) continue; if (d[a1][b1][c1] == -1) { d[a1][b1][c1] = d[a][b][c] + 1; q.push(getnum(a1, b1, c1)); } } } } } } int main() { while (scanf("%d%d%d", &w, &h, &n) && n) { char c = getchar(); while (c != '\n') c = getchar();//消除无效字符 for (int i = 1; i <= h; i++) fgets(M[i] + 1, 20, stdin); cnt = 0; int x[MAXM + 10], y[MAXM + 10]; for (int i = 1; i <= h; i++) for (int j = 1; j <= w; j++) if (M[i][j] != '#') { id[i][j] = ++cnt;//利用矩阵存稀疏图,cnt是每个结点的序号,也代表了最终的结点数 x[cnt] = i; y[cnt] = j; if ('a' <= M[i][j] && M[i][j] <= 'c') st[M[i][j] - 'a'] = cnt; //找每一个鬼 if ('A' <= M[i][j] && M[i][j] <= 'C') ed[M[i][j] - 'A'] = cnt;//找目标位置 } for (int i = 1; i <= cnt; i++) { edge[i] = 0;//edge数组存放第i个结点具有的相邻结点数目 for (int j = 0; j < 5; j++) { int xx = x[i] + cx[j]; int yy = y[i] + cy[j]; if (M[xx][yy] != '#') G[i][++edge[i]] = id[xx][yy];//寻找每个结点的相邻结点,最后一个是自身 } } if (n <= 2)//最多只有两个鬼时,定义其余的数组 { edge[++cnt] = 1; G[cnt][1] = cnt;//虚拟的结点,只是在判断非法情况时能起到辅助作用 st[2] = ed[2] = cnt; } if (n <= 1)//最多只有1个鬼时,定义其余的数组,若满足该情况必满足上一种情况 { edge[++cnt] = 1; G[cnt][1] = cnt; st[1] = ed[1] = cnt; } bfs(); printf("%d\n", d[ed[0]][ed[1]][ed[2]]); } return 0; }