例题7-9 万圣节后的早晨 UVa1601

来源:互联网 发布:java return递归 编辑:程序博客网 时间:2024/05/01 16:01

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 192int 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个(包含自身),因此最后一个值是5int 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; }


0 0
原创粉丝点击