📜  门|门CS 2012 |第 59 题(1)

📅  最后修改于: 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)$。