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

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;
 }


你可能感兴趣的:(搜索,uva,bfs)