UVA 11624 Fire!

在这款迷宫逃脱游戏中,玩家必须帮助Joe在火势蔓延前找到出口。Joe和火势每分钟移动一格,游戏的目标是在火势到达之前找到迷宫的出口。本文详细介绍了游戏规则和算法实现。

Fire!

https://vjudge.net/problem/UVA-11624
Joe works in a maze. Unfortunately, portions of the maze have
caught on fire, and the owner of the maze neglected to create a fire
escape plan. Help Joe escape the maze.
Given Joe’s location in the maze and which squares of the maze
are on fire, you must determine whether Joe can exit the maze before
the fire reaches him, and how fast he can do it.
Joe and the fire each move one square per minute, vertically or
horizontally (not diagonally). The fire spreads all four directions
from each square that is on fire. Joe may exit the maze from any
square that borders the edge of the maze. Neither Joe nor the fire
may enter a square that is occupied by a wall.

Input

The first line of input contains a single integer, the number of test
cases to follow. The first line of each test case contains the two
integers R and C, separated by spaces, with 1 ≤ R, C ≤ 1000. The
following R lines of the test case each contain one row of the maze. Each of these lines contains exactly
C characters, and each of these characters is one of:
• #, a wall
• ., a passable square
• J, Joe’s initial position in the maze, which is a passable square
• F, a square that is on fire
There will be exactly one J in each test case.

Output

For each test case, output a single line containing ‘IMPOSSIBLE’ if Joe cannot exit the maze before the
fire reaches him, or an integer giving the earliest time Joe can safely exit the maze, in minutes.

Sample Input

2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F

Sample Output

3
IMPOSSIBLE

C++

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int MAXN = 1000 + 5;
const int INF = 0x3f3f3f3f;
char maze[MAXN][MAXN];
bool vis[MAXN][MAXN];
int timeFire[MAXN][MAXN];
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
int n, m;

struct node{
	int x, y, step;
};

queue<node> fire;

bool judge(int x, int y)
{
	return x >= 0 && x < n && y >= 0 && y < m;
}

void bfsFire()
{
	node now, next;
	while(!fire.empty())
	{
		now = fire.front();
		fire.pop();
		for(int i = 0; i < 4; i ++)
		{
			int tx = now.x + dir[i][0];
			int ty = now.y + dir[i][1];
			if(judge(tx, ty) && !vis[tx][ty] && maze[tx][ty] != '#')
			{
				vis[tx][ty] = true;
				timeFire[tx][ty] = timeFire[now.x][now.y] + 1;
				next.x = tx;
				next.y = ty;
				fire.push(next);
			}
		}
	}	
}

void bfs(int x, int y)
{
	memset(vis, false, sizeof(vis));
	queue<node> q;
	node now, next;
	now.x = x;
	now.y = y;
	now.step = 0;
	vis[x][y] = true;
	q.push(now);
	while(!q.empty())
	{
		now = q.front();
		q.pop();
		for(int i = 0; i < 4; i ++)
		{
			int tx = now.x + dir[i][0];
			int ty = now.y + dir[i][1];
			if(tx < 0 || tx >= n || ty < 0 || ty >= m)
			{
				printf("%d\n", now.step + 1);
				return;
			}
			if(!vis[tx][ty] && maze[tx][ty] != '#' && now.step + 1 < timeFire[tx][ty])
			{
				vis[tx][ty] = true;
				next.x = tx;
				next.y = ty;
				next.step = now.step + 1;
				q.push(next);
			}
		}
	}
	printf("IMPOSSIBLE\n");
	return;
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T --)
	{
		int sx, sy; node tmp;
		memset(vis, false, sizeof(vis));
		memset(timeFire, INF, sizeof(timeFire));
		scanf("%d%d", &n, &m);
		getchar();
		for(int i = 0; i < n; i ++)
		{
			for(int j = 0; j < m; j ++)
			{
				scanf("%c", &maze[i][j]);
				if(maze[i][j] == 'J'){
					sx = i; sy = j;
				}
				else if(maze[i][j] == 'F'){
					tmp.x = i;
					tmp.y = j;
					fire.push(tmp);
					vis[i][j] = true;
					timeFire[i][j] = 0;
				}
			}
			getchar();
		}
		bfsFire();
		bfs(sx, sy);
	}
	return 0;
}
### UVa 11624 测试数据与题目解析 UVa 11624 是关于 **Variable Radix Huffman Encoding** 的一个问题,其核心在于实现一种基于可变基数的哈夫曼编码算法。以下是对此问题的相关分析以及可能的测试数据。 #### 题目描述 该问题要求处理一组输入数据集,其中每个数据集包含三个部分: - 整数值 \( R \),表示字符集合的最大基数(\( 2 \leq R \leq 10 \))。 - 整数值 \( N \),表示字符的数量(\( 2 \leq N \leq 26 \))。 - 字符频率列表 \( f_1, f_2, ..., f_N \),每个频率范围为 \( 1 \) 到 \( 999 \)[^2]。 目标是通过构建一个最优前缀码树来最小化加权路径长度,并计算总权重。 --- #### 解决思路 为了完成此任务,可以采用优先队列(堆结构)来模拟哈夫曼编码的过程。具体方法如下: 1. 初始化一个优先队列,将所有字符及其对应的频率作为节点加入队列。 2. 当队列中的节点数量大于 \( R \) 时,取出前 \( R \) 小的节点并将其合并成一个新的父节点,新节点的权重等于这 \( R \) 个子节点的权重之和。 3. 将新的父节点重新放回优先队列中。 4. 重复上述过程直到队列中只剩下一个根节点为止。 5. 计算最终的加权路径长度,即为所求的结果。 这种方法的时间复杂度主要取决于优先队列的操作次数和每次操作的成本,通常为 \( O(N \log N) \)[^2]。 --- #### 示例代码 以下是一个简单的 C++ 实现示例: ```cpp #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(0); int R, N; while (cin >> R && R != 0) { // 输入终止条件 cin >> N; // 获取字符数量 priority_queue<int, vector<int>, greater<int>> pq; for (int i = 0; i < N; ++i) { int freq; cin >> freq; pq.push(freq); // 加入优先队列 } long long total_cost = 0; while ((int)pq.size() > 1) { long long sum = 0; for (int i = 0; i < min(R, (int)pq.size()); ++i) { sum += pq.top(); // 取出当前最小值 pq.pop(); } total_cost += sum; // 累计成本 pq.push(sum); // 合并后的节点重新放入队列 } cout << total_cost << "\n"; // 输出结果 } return 0; } ``` --- #### 测试样例 ##### 输入样例 ```plaintext 3 7 10 20 30 40 50 60 70 2 8 1 1 1 1 1 1 1 1 0 0 ``` ##### 输出样例 ```plaintext 410 30 ``` 解释: - 对于第一个数据集 (\( R=3, N=7 \)),经过多次合并得到的总加权路径长度为 \( 410 \)。 - 对于第二个数据集 (\( R=2, N=8 \)),由于所有频率相等,则形成完全二叉树,总加权路径长度为 \( 30 \)。 --- #### 常见错误点 1. 如果未正确判断 `min(R, queue_size)`,可能会导致程序崩溃或逻辑错误。 2. 忽视了当 \( R>N \) 或其他特殊情况下的边界条件可能导致误判。 3. 使用浮点数代替整型存储频率会引入精度误差。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值