题解 【洛谷P1332】血色先锋队

题面:https://www.luogu.org/problemnew/show/P1332

很容易看出,这是一个典型的广度优先搜索,也就是众多OIer口中的bfs。

先给各位普及一下bfs(部分来自百度):

广度优先搜索(Breadth-First Search),又称作宽度优先搜索,或横向优先搜索,简称bfs,是一种基础算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点,如果发现目标,则演算终止。广度优先搜索的实现一般采用队列。

其实,广度优先搜索是搜索算法的基础,想要成为一名优秀的OIer,广度优先搜索和深度优先搜索都是必须掌握的!

此题告诉了我们有A个感染源,B个领主,我们可以定义一个vis数组,若当前坐标的vis值为1,那么此处就没有被感染;否则,当前坐标就已被感染。

我们可以首先用bfs算出每个坐标被感染的时间,最后直接输出领主被感染的时间即可。

话不多说,上代码:

#include<bits/stdc++.h>//万能头文件
using namespace std;//开启标准名字空间
struct Node
{
    int x,y,Time;//x为横坐标,y为纵坐标,Time为被感染时间
} s[250010];//设置结构体数组维护队列
int head,tail;//分别为头指针、尾指针
int n,m,a,b,vis[505][505],c[250010],d[250010],e,f,i,j,
    k;//vis的意义同分析,c数组和d数组为感染源坐标,e、f为领主坐标
int P[510][510];//每个坐标被感染时间
void bfs()  //开始bfs
{
    tail=0;
    head=0;//初始化指针
    for(i=1; i<=a; i++)  //先把已知条件加入队列,并初始化时间
    {
        s[++tail].x=c[i];//相当于tail++,s[tail].x=c[i]
        s[tail].y=d[i];
        s[tail].Time=0;
        P[c[i]][d[i]]=0;
    }
    while(head<tail)  //如果队列中还有元素
    {
        head++;//头指针加1
        int h=s[head].x,r=s[head].y,tmp=s[head].Time;//取出队首元素
        if(h+1<=n && vis[h+1][r]==0)  //往右扩展,若合法加入队列
        {
            s[++tail].x=h+1;//更新x坐标
            s[tail].y=r;//更新y坐标
            P[h+1][r]=s[tail].Time=tmp+1;//更新时间
            vis[h+1][r]=1;//记录为已被感染
        }
        //以下每步操作意义同上
        if(h-1>=1 && vis[h-1][r]==0)  //往左扩展,若合法加入队列
        {
            s[++tail].x=h-1;
            s[tail].y=r;
            P[h-1][r]=s[tail].Time=tmp+1;
            vis[h-1][r]=1;
        }
        if(r+1<=m && vis[h][r+1]==0)  //往上扩展,若合法加入队列
        {
            s[++tail].x=h;
            s[tail].y=r+1;
            P[h][r+1]=s[tail].Time=tmp+1;
            vis[h][r+1]=1;
        }
        if(r-1>=1 && vis[h][r-1]==0)  //往下扩展,若合法加入队列
        {
            s[++tail].x=h;
            s[tail].y=r-1;
            P[h][r-1]=s[tail].Time=tmp+1;
            vis[h][r-1]=1;
        }
    }
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&a,&b);//输入矩阵大小、感染源个数和领主个数
    for(i=1; i<=a; i++)
    {
        scanf("%d%d",&c[i],&d[i]);//输入感染源坐标
        vis[c[i]][d[i]]=1;//记录为已被感染
    }
    bfs();//遍历每个坐标被感染的时间
    for(i=1; i<=b; i++)
    {
        scanf("%d%d",&e,&f);//输入领主坐标
        printf("%d\n",P[e][f]);//直接输出被感染时间
    }
    return 0;//结束
}

 

有些人直接枚举每一个领主和感染源,求他们曼哈顿距离,但在矩阵过大时会TLE,所以bfs总是比暴力好的。

posted @ 2019-02-21 19:20  csxsi  阅读(222)  评论(0编辑  收藏  举报