题意
n
×
m
n \times m
n×m的地图
x
x
x是墙
.
.
.是空白位置
1
1
1是人
p
p
p是敌方乐队位置
挑一个点 空白或者是行人所在位置开演唱会 每个行人会根据我们乐队和敌方乐队哪个距离近 就去听哪个演唱会 如果最短距离一样 就来听我们的
求我们最多能获得多少观众
出题人题解
简单搜索题,从每个标记为 1 的地方出发进行bfs,遍历全图得到其到每个点的距离,同时找到离敌方乐队的最近距离,令图上所有距离小于等于该最近距 离的位置的贡献加1,最终找出所有合法位置里的最大贡献即可。
思路
每次bfs时间复杂度应该是
O
(
n
m
)
O(nm)
O(nm)
然后以每个人所在点为起点bfs 一共最多100 个人
n
,
m
<
=
500
n,m<=500
n,m<=500 所以
n
×
m
<
=
2.5
e
5
n\times m<=2.5e5
n×m<=2.5e5
总的复杂度在乘上100 大概是1e7级别的 能够接受
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define ar2 array<int,2>
#define ar3 array<int,3>
#define ar4 array<int,4>
#define endl '\n'
void cmax(int &a,int b){a=max(a,b);}
void cmin(int &a,int b){a=min(a,b);}
const int N=510,MOD=1e9+7,INF=0x3f3f3f3f,LINF=LLONG_MAX;
char g[N][N];
int val[N][N],dis[N][N];
/*
val表示每个点的贡献 意思就是这个如果在这个点上开演唱会 会有多少人会来看
dis数组其实是在每次的bfs中使用的 每次bfs的时候初始化一下
*/
int n,m;
vector<pii>people;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
void bfs(int sx,int sy){
memset(dis,0x3f,sizeof dis);
queue<pii>q;
q.emplace(sx,sy);
dis[sx][sy]=0;
int mn=INF;//mn表示距离当前这个起点行人最近的地方乐队的距离 后面要根据这个距离计算每个点的贡献
while(q.size()){
auto [x,y]=q.front();q.pop();
for(int i=0;i<4;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx<1||tx>n||ty<1||ty>m||g[tx][ty]=='x') continue;
if(dis[tx][ty]>dis[x][y]+1){
dis[tx][ty]=dis[x][y]+1;
q.emplace(tx,ty);
}
if(g[tx][ty]=='p'){
cmin(mn,dis[tx][ty]);
}
}
}
//计算贡献
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(dis[i][j]<=mn){
val[i][j]++;
}
}
}
}
void solve() {
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>g[i][j];
if(g[i][j]=='1'){
people.push_back({i,j});
}
}
}
for(auto [x,y]:people){
bfs(x,y);
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j]=='p'||g[i][j]=='x') continue;
cmax(ans,val[i][j]);
}
}
cout<<ans<<endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t=1;
// cin>>t;
while (t--) solve();
}