链接:https://ac.nowcoder.com/acm/contest/118/A
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
最近,喜爱ACM的PBY同学沉迷吃鸡,无法自拔,于是又来到了熟悉的ERANGEL。经过一番搜寻,PBY同学准备动身前往安全区,但是,地图中埋伏了许多LYB,PBY的枪法很差,希望你能够帮他找到一条路线,每次只能向上、下、左、右移动,尽可能遇到较少的敌人。
输入描述:
题目包含多组测试,请处理到文件结束;
第一行是一个整数n,代表地图的大小;
接下来的n行中,每行包含n个整数a,每个数字a代表当前位置敌人的数量;
1 < n <= 100,1 <= a <= 100,-1代表当前位置,-2代表安全区。
输出描述:
对于每组测试数据,请输出从当前位置到安全区所遇到最少的敌人数量,每个输出占一行。
示例1
输入
5
6 6 0 -2 3
4 2 1 2 1
2 2 8 9 7
8 1 2 1 -1
9 7 2 1 2
输出
9
示例2
输入
5
62 33 18 -2 85
85 73 69 59 83
44 38 84 96 55
-1 11 90 34 50
19 73 45 53 95
输出
173
解题思路:
求从起点到终点遇到最少的敌人的情况的数量,该问题可以看成求从起点到任意一点的最少敌人数量,而求从起点到起点周围一点最少敌人数量是已知的(即起点敌人数+目标点敌人数),因此可以从起点周围逐步推导出到所有点最少敌人数量,也就求出到终点的敌人数量。
对地图搜索可以采用DFS和BFS两种方式。但是DFS会每搜索一个节点就会遍历全图更新每个节点的敌人数量(可以调试代码观察bp数组的变化情况),搜索次数太多导致TLE。而BFS会从起点开始逐圈搜索,每到一个节点仅会将相邻需要更新的节点入队等待更新,相比DFS而言更新最少敌人数量可以“一步到位”,减少了更新次数。
DFS代码(TLE):
#include <iostream>
using namespace std;
//a存储所有位置敌人数量,bp存储从起点到每个点最少敌人数量
int n, a[101][101], bp[101][101];
void dfs(int x, int y,int new_value){
//更新敌人数量
bp[x][y] = new_value;
//搜寻四个方向,如果更新了就拓展路径继续更新
//如果未越界 且 未遍历过或者走到该点遇到的敌人数可以更少
if(x + 1 < n && (bp[x + 1][y] == -1 || new_value + a[x + 1][y] < bp[x + 1][y])){
dfs(x + 1, y, new_value + a[x + 1][y]);
}
if(x - 1 >= 0 && (bp[x - 1][y] == -1 || new_value + a[x - 1][y] < bp[x - 1][y])){
dfs(x - 1, y, new_value + a[x - 1][y]);
}
if(y + 1 < n && (bp[x][y + 1] == -1 || new_value + a[x][y + 1] < bp[x][y + 1])){
dfs(x, y + 1, new_value + a[x][y + 1]);
}
if(y - 1 >= 0 && (bp[x][y - 1] == -1 || new_value + a[x][y - 1] < bp[x][y - 1])){
dfs(x, y - 1, new_value + a[x][y - 1]);
}
}
int main(){
//startxy存储起始坐标,finishxy存储目标坐标
int sx, sy, fx, fy;
cin >> n;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
//初始化
bp[i][j] = -1;
cin >> a[i][j];
if(a[i][j] == -1){
a[i][j] = 0;
sx = i;
sy = j;
}
if(a[i][j] == -2){
a[i][j] = 0;
fx = i;
fy = j;
}
}
}
dfs(sx, sy, 0);
cout << bp[fx][fy] << endl;
}
AC代码(BFS):
#include <iostream>
#include <queue>
using namespace std;
int main() {
int n;
while(cin >> n) {
//a存储所有位置敌人数量,startxy存储起始坐标,finishxy存储目标坐标,bp存储从起点到每个点最少敌人数量
int a[101][101], sx, sy, fx, fy, bp[101][101];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
//初始化
bp[i][j] = -1;
cin >> a[i][j];
if(a[i][j] == -1) {
//起始点敌人数量为0
a[i][j] = 0;
sx = i;
sy = j;
}
if(a[i][j] == -2) {
a[i][j] = 0;
fx = i;
fy = j;
}
}
}
//BFS 用队列
queue<int> q;
//将二维坐标转化为一维
q.push(sx * n + sy);
//初始化起点
bp[sx][sy] = 0;
while(!q.empty()) {
int x = q.front() / n, y = q.front() % n;
q.pop();
//搜寻四个方向,如果更新了就加入队列等待继续更新
//如果未越界 且 未遍历过或者走到该点遇到的敌人数可以更少
if(x + 1 < n && (bp[x + 1][y] == -1 || bp[x][y] + a[x + 1][y] < bp[x + 1][y])) {
bp[x + 1][y] = bp[x][y] + a[x + 1][y];
q.push((x + 1) * n + y);
}
if(x - 1 >= 0 && (bp[x - 1][y] == -1 || bp[x][y] + a[x - 1][y] < bp[x - 1][y])) {
bp[x - 1][y] = bp[x][y] + a[x - 1][y];
q.push((x - 1) * n + y);
}
if(y + 1 < n && (bp[x][y + 1] == -1 || bp[x][y] + a[x][y + 1] < bp[x][y + 1])) {
bp[x][y + 1] = bp[x][y] + a[x][y + 1];
q.push(x * n + (y + 1));
}
if(y - 1 >= 0 && (bp[x][y - 1] == -1 || bp[x][y] + a[x][y - 1] < bp[x][y - 1])) {
bp[x][y - 1] = bp[x][y] + a[x][y - 1];
q.push(x * n + (y - 1));
}
}
cout << bp[fx][fy] << endl;
}
}
优化解法:
使用普通队列queue的BFS虽然可以求解,但是需要等到图全部搜索完毕才能得到答案。而除了(从起点到终点的)路径上的(点的)最少敌人数量都是不需要的,因此可以使用优先队列简化搜索流程,搜索到终点时立刻得出答案而不需要全部搜索完毕再得出答案。稍后更新。