试题编号: | 201604-4 |
试题名称: | 游戏 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小明在玩一个电脑游戏,游戏在一个n×m的方格图上进行,小明控制的角色开始的时候站在第一行第一列,目标是前往第n行第m列。 输入格式 输入的第一行包含三个整数n, m, t,用一个空格分隔,表示方格图的行数n、列数m,以及方格图中有危险的方格数量。 输出格式 输出一个整数,表示小明最快经过几个时间单位可以过关。输入数据保证小明一定可以过关。 样例输入 3 3 3 样例输出 6 样例说明 第2行第1列时刻1是危险的,因此第一步必须走到第1行第2列。 评测用例规模与约定 前30%的评测用例满足:0 < n, m ≤ 10,0 ≤ t < 99。
|
问题链接:CCF201604试题。
问题描述:(参见上文)。
问题分析:
这是一个求最短路径的问题,即求最优问题,通常用BFS(广度优先搜索)来实现。本题也用BFS来实现,比较难以考虑到的是,需要一个三维的标志来避免重复搜索。除了行列坐标外,还需要考虑时间因素,所以是三维的。因为一些格在某个时间范围是危险的,不可进入,但是这个时间范围之外,是可以随意进入的。所以有时候需要在一些地方踱步,等过了这段时间再前行,就不能简单地限制为进入过的格不能再进入。
程序说明:
把格的危险时间范围存储在数组visited[][][]中,使得程序逻辑变得更加简洁,同时也节省了存储。其他都是套路。
数组visited[][][]的第3维坐标之所以为300+1,是计算出来的。从左上角到右下角最多走200步,时间范围a,b<=100,那么安全走到右下角使用的最多时间<=300,下标0不使用,所以是300+1。
提交后得100分的C++语言程序如下:
/* CCF201604-4 游戏 */
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 100;
const int DIRECTSIZE = 4;
struct direct {
int drow, dcol;
} direct[DIRECTSIZE] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int visited[N+1][N+1][300+1];
struct node {
int row, col, level;
};
int bfs(int n, int m)
{
node start, front, v;
start.row = 1;
start.col = 1;
start.level = 0;
queue<node> q;
q.push(start);
while(!q.empty()) {
front = q.front();
q.pop();
// 到达终点则结束
if(front.row == n && front.col == m)
return front.level;
for(int i=0; i<DIRECTSIZE; i++) {
// 移动一格
v.row = front.row + direct[i].drow;
v.col = front.col + direct[i].dcol;
v.level = front.level + 1;
// 行列越界则跳过
if(v.row < 1 || v.row > n || v.col < 1 || v.col > m)
continue;
// 已经访问过的点不再访问
if(visited[v.row][v.col][v.level])
continue;
// 向前搜索:标记v点为已经访问过,v点加入队列中
visited[v.row][v.col][v.level] = 1;
q.push(v);
}
}
return 0;
}
int main()
{
int n, m, t, r, c, a, b;
// 变量初始化
memset(visited, 0, sizeof(visited));
// 输入数据
cin >> n >> m >> t;
for(int i=1; i<=t; i++) {
cin >> r >> c >> a >> b;
// 设置方格危险时间,使之那些时间不可进入
for(int j=a; j<=b; j++)
visited[r][c][j] = 1;
}
// BFS搜索
int ans = bfs(n, m);
// 输出结果
cout << ans << endl;
return 0;
}