洛谷Oj-01迷宫-广度优先搜索

来源:互联网 发布:石青软件官网 编辑:程序博客网 时间:2024/04/29 14:40

问题描述
有一个仅由数字0与1组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
对于:
2 2
01
10
1 1
2 2
输出:
4
4
AC代码

int book[1001][1001];//book有两个作用①标记点是否走过②记录连通块的大小char a[1001][1001];//储存迷宫int next1[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//右下左上四个方向struct node{    int x;    int y;};struct node que[1000000];//1000*1000=1000000int main(){    //freopen("in.txt","r",stdin);    int n,m,i,j,k;    int head,tail;    int sx,sy;    scanf("%d%d",&n,&m);    for(i=0;i<=n-1;i++)        scanf("%s",a[i]);//虽然二维数组a中的0、1是字符形式,但是不影响算法,因此无需进行转换    for(i=1;i<=m;i++)    {        scanf("%d%d",&sx,&sy);//因为数组下标是0到n-1,所以之后要用到sx,sy时都要将其减1        if(book[sx-1][sy-1]==0)//如果该点未被标记,就需要扩展该点        {            sum=0;//重置变量            head=1;            tail=1;            que[tail].x=sx-1;//入队            que[tail].y=sy-1;            tail++;            book[sx-1][sy-1]=1;//标记            while(head<tail)//队列不为空            {                int tx,ty;                for(j=0;j<=3;j++)                {                    tx=que[head].x+next1[j][0];                    ty=que[head].y+next1[j][1];                    if(tx<0||tx>n-1||ty<0||ty>n-1)//越界                        continue;                    if(book[tx][ty]==0&&a[tx][ty]!=a[que[head].x][que[head].y])//(tx,ty)没被标记且值与(que[head].x],[que[head].y)不同                    {                        que[tail].x=tx;//入队                        que[tail].y=ty;                        tail++;                        book[tx][ty]=1;//标记                    }                }                head++;//继续扩展下一个点            }            for(k=1;k<=tail-1;k++)//对tail充分利用,很巧妙                book[que[k].x][que[k].y]=tail-1;//将连通块的大小赋给联通块内的每一个点,该值>=1            printf("%d\n",book[sx-1][sy-1]);//打印结果        }            else//不等于0说明book[sx-1][sy-1]的值就是连通块的大小                printf("%d\n",book[sx-1][sy-1]);//打印结果    }    return 0;}

算法描述
本题极易TLE,说到记忆化我们很容易想到先将所有的联通块都求出来,再看点在哪个连通块内就好了,但这样可能会求出并不需要求出的连通块,导致超时。如果不记忆化的话,思路就是给出一个点计算一个点,不过这样可能会重复计算,导致超时。本题解的巧妙之处就在于通过if语句将记忆化与给一个点算一个点相结合,避免了做无用功