思路:
首先将所有的绿洲加入队列中,每次从队列中取一个元素,查询周围的8个坐标(需要注意边界条件)的最小距离是否可以被更新,如果相邻坐标被更新则将该坐标加入队列中。
代码:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define MAX 100000000
struct Pos
{
int x, y;
};
void bfs(queue<Pos>& q, vector<vector<int> >& f);
// 可以走的周围的八个格子,可以自己画一下
int d[8][2] = { {-1,-1},{0,-1},{1,-1},
{-1,0},{1,0},
{-1,1},{0,1},{1,1}
};
int n, m, p;
int main()
{
cin >> n >> m >> p;
vector<vector<int> > f(n + 1, vector<int>(n + 1, MAX)); // 地图,存储从一个坐标到绿洲的最短距离
for (int i = 0; i < m; i++)
{
int x, y;
cin >> x >> y;
f[x][y] = -1; // 毒蛇
}
queue<Pos> q;
for (int i = 0; i < p; i++)
{
int x, y;
cin >> x >> y;
Pos tmp;
tmp.x = x;
tmp.y = y;
q.push(tmp); // 把绿洲加入到队列中,绿洲到本身距离为0
f[x][y] = 0;
}
bfs(q, f);
long long res = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (f[i][j] == MAX) f[i][j] = -1; // 如果这个坐标没有被更新,表明从这个点到不了任何一个绿洲
res += f[i][j];
}
}
cout << res << endl;
return 0;
}
void bfs(queue<Pos>& q, vector<vector<int> >& f)
{
while (!q.empty())
{
Pos tmp = q.front();
q.pop();
for (int i = 0; i < 8; i++) // 遍历八个方向
{
int x = tmp.x + d[i][0];
int y = tmp.y + d[i][1];
if (x <= n && x >= 1 && y <= n && y >= 1 && f[x][y] > 0) // 处理越界,该坐标是绿洲或毒蛇时不更新
{
if (f[tmp.x][tmp.y] + 1 < f[x][y]) // 如果被更新,将该坐标加入到队列中,因为与之相邻的坐标到绿洲的最小距离可能由从该点走而变短
{
f[x][y] = f[tmp.x][tmp.y] + 1;
Pos pos;
pos.x = x;
pos.y = y;
q.push(pos);
}
}
}
}
}