📅  最后修改于: 2023-12-03 14:58:37.397000             🧑  作者: Mango
本题是门|门CS 2012中的第59题,题目名称为“守卫要塞”,要求解决一个搜索问题。
有一座要塞,要塞被分割成了 $N\times M$ 的一个网格图,其中一些点上有岗哨。 岗哨可以向它正东、正南、正西、正北四个方向看守,它的视野是向这个方向最近的岗哨。现在有一些守卫要塞,要求从它们中找出一个最多能够被其他守卫看到的守卫。输出这个数目。
输入格式:
第一行是两个整数 $N$ 和 $M$,表示有 $N$ 行,$M$ 列的网格图。以下 $N$ 行每行 $M$ 个字符,”@“表示该位置上有守卫,”.”表示该位置上没有守卫。
输出格式:
输出其中最多能够被其他守卫看到的守卫的个数。
$1\leq N, M \leq 500$
这道题的核心是搜索,对于网格图中的每个守卫,遍历其四个方向,分别判断在此方向上是否能看到其他守卫。为了避免重复计算,可以使用一个 map ,保存已经计算过的位置。在遍历每个守卫时,可以通过 map 判断此守卫是否已经计算过,如果已经计算过,则直接取其计算结果即可。
最后,统计所有守卫所能看到的最多守卫数,即可得到题目答案。
具体实现请参考下面的代码。
#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
char a[510][510];
int vis[510][510];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
queue<pair<int,int> >q;
map<pair<int,int>,int>mp;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {cin>>a[i][j];if(a[i][j]=='@') vis[i][j]=1;}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(vis[i][j])
{
mp.clear();
q.push(make_pair(i,j));
mp[make_pair(i,j)]=1;
int tot=1;//这个守卫能看到多少守卫
while(!q.empty())
{
auto now=q.front();q.pop();
for(int k=0;k<4;k++)
{
int nx=now.first+dx[k],ny=now.second+dy[k];
if(nx<1||nx>n||ny<1||ny>m||mp[make_pair(nx,ny)]) continue;
if(vis[nx][ny]) mp[make_pair(nx,ny)]=1, tot++;
q.push(make_pair(nx,ny));
}
}
ans=max(ans,tot);
}
}
}
cout<<ans<<endl;
return 0;
}
本题的时间复杂度是 $O(n^2m^2)$,其中 $n$ 表示网格图的行数,$m$ 表示网格图的列数。在最坏情况下,所有守卫都需要遍历一遍整个网格图,因此时间复杂度为 $O(n^2m^2)$。