河南萌新联赛2024第(二)场---G. lxy的通风报信

题目描述

在 nnn × mmm 的平面星球里( 5<=n5 <= n5<=n, m<=1000m <= 1000m<=1000 ),存在着 aaa 支军队 ( 2<=a<=502 <= a <= 502<=a<=50 ) , 和 bbb 支驻扎在地图中的敌军 ( 0<=b<=n∗m−a0 <= b <= n * m - a0<=b<=n∗m−a ) ,你需要确保所有军队全部合并 .

军队坐标假设为 ( xix_ixi​ , yiy_iyi​ ) ,行军一天可以到达( xi+1x_{i + 1}xi+1​ , yiy_iyi​ )或者 ( xi−1x_{i - 1}xi−1​ , yiy_iyi​ ) 或者( xix_ixi​ , yi+1y_{i + 1}yi+1​ ) 或者 ( xix_ixi​ , yi−1y_{i - 1}yi−1​ ),在与另外一支军队相遇时自动合并到另一支军队,你的部队需要避免与敌军起冲突。

战事紧急,身为司令,你需要快速计算出最少多少天所有军队全部合并完毕,如果必须跟敌军发生冲突请输出 No ,否则输出最少的天数。

注意:

在一支军队移动时,其他军队不可移动。

军队合并是依次进行的,且起点和终点都必须是军队,起点终点不固定,每次行军,可以任意指定两个现存在地图中的不同军队作为起点终点。例如有三个军队A,B,C,A->B,A合并B,B再合并C。也可以A->B,C->B。

输入描述:

输入nnn ,mmm(5<=n5 <= n5<=n, m<=1000m <= 1000m<=1000)
输入nnn行,每行mmm列,
每列用∗*∗ 表示军队
# 表示敌军
... 表示可移动区域。

输出描述:

如果军队之间可以全部合并,输出需要多少步
反之输出No

示例1

输入

复制5 5 .#..# ..#*. *...* #.### .....

5 5
.#..#
..#*.
*...*
#.###
.....

输出

复制6

6

说明

 

示例2

输入

复制5 5 ##### #.... ***## *#..# *####

5 5
#####
#....
***##
*#..#
*####

输出

复制4

4

示例3

输入

复制5 5 .#*#. #.#.# ..*.. *.#.* .....

5 5
.#*#.
#.#.#
..*..
*.#.*
.....

输出

复制No

No

做法

看到题目时完全是懵的,完全不知道怎么实现。看了题解说是bfs求每个点之间的距离,然后建边,然后跑一遍最小生成树。感觉还得有抽象问题的能力吧。最近也遇到挺多看上去很难的题,但看了题解后其实很多自己是学过的,而且知道后很快能写出来。

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
char a[1010][1010];
int vis[1010][1010],id[1010][1010],head[100];
int dx[]={0,0,-1,1};
int dy[]={1,-1,0,0};

struct ty{
    int x,y;  
    int cnt;
};

vector<ty> v;
queue<ty> q;
int sign,tot,ans;

struct ty2{
    int l,next,t;  
}edge[10000];

void addedge(int x,int y,int z){
    edge[++tot].l=z;
    edge[tot].t=y;
    edge[tot].next=head[x];
    head[x]=tot;
}

struct ty3{
    int x,len;
    bool operator < (const ty3 & a) const{
        return len>a.len;
    }
};

int len[100],vis1[100];
priority_queue<ty3> q1;

void prime(){
    memset(len,0x3f,sizeof(len));
    memset(vis,0,sizeof(vis));
    vis1[id[v[1].x][v[1].y]]=1;
    len[id[v[1].x][v[1].y]]=0;
    for(int i=head[id[v[1].x][v[1].y]];i!=-1;i=edge[i].next){
        q1.push({edge[i].t,edge[i].l});
        len[edge[i].t]=edge[i].l;
    }
    
    while(!q1.empty()){
        ty3 tmp=q1.top();
        q1.pop();
        if(vis1[tmp.x]) continue;
        ans+=tmp.len;
  
        vis1[tmp.x]=1;
        for(int i=head[tmp.x];i!=-1;i=edge[i].next){
            if(vis1[edge[i].t]) continue;
            if(len[edge[i].t]>edge[i].l){
                len[edge[i].t]=edge[i].l;
                q1.push({edge[i].t,edge[i].l});
            }
        }
    }
}

void bfs(int x){
    int res=0;
    q.push({v[x].x,v[x].y,0});
    memset(vis,0,sizeof(vis));
    while(!q.empty()){
        ty tmp=q.front();
        q.pop();
        if(vis[tmp.x][tmp.y]) continue;
        vis[tmp.x][tmp.y]=1;
        if(a[tmp.x][tmp.y]=='*'&&(tmp.x!=v[x].x||tmp.y!=v[x].y)){
            addedge(id[v[x].x][v[x].y],id[tmp.x][tmp.y],tmp.cnt);
            res++;
        }
        for(int i=0;i<4;i++){
            int xx=dx[i]+tmp.x;
            int yy=dy[i]+tmp.y;
            if(xx>n||xx<1||yy>m||yy<1) continue;
            if(vis[xx][yy]) continue;
            if(a[xx][yy]=='#') continue;
            q.push({xx,yy,tmp.cnt+1});
        }
    }

    if(res+1!=cnt) sign=1;
    
}

int main(){
    memset(head,-1,sizeof(head));
    v.push_back({-1,-1,0});
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            if(a[i][j]=='*') {
                cnt++;
                v.push_back({i,j,0});
                id[i][j]=v.size()-1;
            }
        }
    }
    

    
    for(int i=1;i<v.size();i++){
        bfs(i);
        if(sign){
            cout<<"No";
            return 0;
        }
    }
    
    prime();
    
    cout<<ans;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值