Aizu - 0558 多源bfs

题目

在H * W的地图上有N个奶酪工厂,每个工厂分别生产硬度为1~N的奶酪。有一只老鼠准备从出发点吃遍每一个工厂的奶酪。老鼠有一个体力值,初始时为1,每吃一个工厂的奶酪体力值增加1(每个工厂只能吃一次),且老鼠只能吃硬度不大于当前体力值的奶酪。 老鼠从当前格到上下左右相邻的无障碍物的格需要时间1单位,有障碍物的格不能走。走到工厂上时即可吃到该工厂的奶酪,吃奶酪时间不计。问吃遍所有奶酪最少用时

输入

第一行三个整数H(1 <= H <= 1000)、W(1 <= W <=1000)、N(1 <= N <= 9),之后H行W列为地图, “.“为空地, ”X“为障碍物,”S“为老鼠洞,N表示有N个生产奶酪的工厂,硬度为1-N。

输出

输出一个整数,代表老鼠吃遍所有奶酪的最少时间花费。

样例

输入样例1

3 3 1
S..
...
..1

输出样例1

4

输入样例2

4 5 2
.X..1
....X
.XX.S
.2.X.

输出样例2

12

输入样例3

10 10 9
.X...X.S.X
6..5X..X1X
...XXXX..X
X..9X...X.
8.X2X..X3X
...XX.X4..
XX....7X..
X..X..XX..
X...X.XX..
..X.......

输出样例3

91

分析

从起点开始对下一个工厂做bfs,每bfs一次将最后这个工厂的位置改为'.',并将起点改为当前工厂的点,

因此输入的时候就要将这n个工厂存入结构体数组

代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstdlib>
using namespace std;

struct point {//用来存点的信息的结构体
	int x;
	int y;
	char c;
};
int h, w, n;
char inp[1002][1002];//输入地图用的
int map[1002][1002];
char nub[12] = "0123456789";//用来把数字转换成字符串,这样nub[n]就是n对应的字符
struct point bfs(struct point s, struct point a);
void show() {//用于展示当前地图状态用于检查老鼠的移动
	printf("\n");
	int i, j;
	for (i = 0; i < h; i++) {
		for (j = 0; j < w; j++) {
			if (map[i][j] == -1) {
				printf("%c", inp[i][j]);
			} else {
				printf("@");
			}
		}
		printf("\n");
	}
}
struct point aim[12];
void show_aim(int n) {//输出当前的目标
	int i;
	for (i = 1; i <= n; i++) {
		printf("%d %d %c\n", aim[i].x, aim[i].y, aim[i].c);
	}
}
bool jgsz(struct point n) {//判断该字符是不是一个数字
	if (inp[n.x][n.y] >= '0' && inp[n.x][n.y] <= '9') {
		return true;
	} else {
		return false;
	}
}
bool jg(struct point n, struct point a) {//判断这个点是否符合bfs的要求
	if (n.x > -1 && n.x < h && n.y > -1 && n.y < w && (map[n.x][n.y] == -1) && (inp[n.x][n.y] == '.'
	        || jgsz(n) ) ) {
		return true;
	} else {
		return false;
	}
}
int main() {
	//printf("%c %d\n", nub[2], nub[2]);//测试一下整整型和字符的转换
	scanf("%d %d %d", &h, &w, &n);//读入第一行的三个数
	if (h == 1 && w == 1) {
		printf("0\n");
		return 0;
	}
	getchar();
	struct point s;//用来存起点的结构体
	int sum = 0; //步数容器
	int i, j, k;
	for (i = 0; i <= n; i++) {
		aim[i].c = i + '0';
	}
	for (i = 0; i < h; i++) {
		for (j = 0; j < w; j++) {
			scanf("%c", &inp[i][j]);
			//	printf("i%dj%d\n", i, j);//test
			if (inp[i][j] == 'S') {//存入起点
				s.x = i;
				s.y = j;
				s.c = 'S';
			}
			for (k = 1; k < 10; k++) {
				if (inp[i][j] == aim[k].c) {
					aim[k].x = i;
					aim[k].y = j;
				}
			}
		}
		getchar();
	}
	//show();
	//show_aim(n);
	sum = 0;
	for (k = 1; k <= n; k++) {
		for (i = 0; i < h; i++) {
			for (j = 0; j < w; j++) {
				map[i][j] = -1;
			}
		}
		inp[s.x][s.y]='.';//在bfs之前将起点改为'.'(即可通过状态)
		struct point ans = bfs(s, aim[k]);
		s.x = ans.x;
		s.y = ans.y;
		//printf("<==no:%d step:%d\n", k, map[s.x][s.y]);
		sum += map[s.x][s.y];
	}
	printf("%d\n", sum);
}
struct point bfs(struct point s, struct point a) {
	struct point n;
	struct point nw;
	queue<point> q;
	q.push(s);
	map[s.x][s.y] = 0;
	while (!q.empty()) {
		//	printf("!!\n");
		n = q.front();
		q.pop();
		if (inp[n.x][n.y] == a.c) {
			//inp[n.x][n.y] = 'N';
			//show();
			inp[n.x][n.y] = '.';
			break;
		}
		nw.x = n.x;
		nw.y = n.y + 1;
		if (jg(nw, a)) {
			q.push(nw);
			//	show();
			map[nw.x][nw.y] = map[n.x][n.y] + 1;
			//	printf("==>%d\n", map[nw.x][nw.y]);
		}
		nw.x = n.x;
		nw.y = n.y - 1;
		if (jg(nw, a)) {
			q.push(nw);
			//	show();
			map[nw.x][nw.y] = map[n.x][n.y] + 1;
			//	printf("==>%d\n", map[nw.x][nw.y]);
		}
		nw.x = n.x + 1;
		nw.y = n.y;
		if (jg(nw, a)) {
			q.push(nw);
			//	show();
			map[nw.x][nw.y] = map[n.x][n.y] + 1;
			//	printf("==>%d\n", map[nw.x][nw.y]);
		}
		nw.x = n.x - 1;
		nw.y = n.y;
		if (jg(nw, a)) {
			q.push(nw);
			//show();
			map[nw.x][nw.y] = map[n.x][n.y] + 1;
			//printf("==>%d\n", map[nw.x][nw.y]);
		}
	}
	return n;
}

反思

最开始没有注意到“体力”的设定,直接对所有数字进行了bfs,导致最后输出不正确

后来没有修改起点为'.',导致总是wa一个点

估计是长这样的一个输入

输入
3 5 2
X2X
X.X
XSX
X.X
X1X

这样如果没有把起点改成'.'的话,bfs完第一个之后走不到第二个会报WA

posted @ 2022-11-02 17:19  ~Chitoge  阅读(16)  评论(0)    收藏  举报