[2025zjgsu校赛]G 演唱会

在这里插入图片描述

题意

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();

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值