zoukankan      html  css  js  c++  java
  • 洛谷 P1141 01迷宫题解

    题目链接:https://www.luogu.org/problem/P1141

    题目描述

    有一个仅由数字00与11组成的n imes nn×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。

    你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

    输入格式

    11行为两个正整数n,mn,m。

    下面nn行,每行nn个字符,字符只可能是00或者11,字符之间没有空格。

    接下来mm行,每行22个用空格分隔的正整数i,ji,j,对应了迷宫中第ii行第jj列的一个格子,询问从这一格开始能移动到多少格。

    输出格式

    mm行,对于每个询问输出相应答案。

    输入输出样例

    输入 #1
    2 2
    01
    10
    1 1
    2 2
    
    输出 #1
    4
    4
    

    说明/提示

    所有格子互相可达。

    对于20\%20%的数据,n≤10n10;

    对于40\%40%的数据,n≤50n50;

    对于50\%50%的数据,m≤5m5;

    对于60\%60%的数据,n≤100,m≤100n100,m100;

    对于100\%100%的数据,n≤1000,m≤100000n1000,m100000。


    题解

    先介绍采用裸的BFS,当然不能满分。再介绍如何优化得到满分。

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <math.h>
     4 #include <algorithm>
     5 #include <string.h>
     6 
     7 using namespace std;
     8 
     9 struct Node
    10 {
    11     int x, y;
    12 };
    13 Node q[1000005]; 
    14 
    15 const int MAXN = 1005;
    16 int n, m, a, b, c, d, front, last, step; 
    17 int pos[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
    18 char abc[MAXN][MAXN]; // 存储输入的矩阵信息 
    19 bool vis[MAXN][MAXN]; // 是否已经遍历过该点 
    20 
    21 
    22 void bfs()
    23 {
    24     Node now;
    25     now.x = a;
    26     now.y = b;
    27     vis[a][b] = 1;
    28     
    29     front = last = 0;
    30     q[last] = now;
    31     last++;
    32     while(front < last)
    33     {
    34         now = q[front++];
    35         for(int i = 0; i < 4; i++)
    36         {
    37             int nx = now.x + pos[i][0]; 
    38             int ny = now.y + pos[i][1]; 
    39             if(nx <= n && nx > 0 && ny <= n && ny > 0 
    40                 && vis[nx][ny] == false 
    41                 && abc[now.x][now.y] != abc[nx][ny]) 
    42             {
    43                 vis[nx][ny] = true;
    44                 q[last].x = nx;
    45                 q[last].y = ny;
    46                 step++;
    47                 last++;
    48             }
    49         } 
    50     }
    51 }
    52 
    53 int main()
    54 {
    55     cin >> n >> m;
    56     for(int i = 1; i <= n; i++)
    57     {
    58         for(int j = 1; j <= n; j++)
    59         {
    60             cin >> abc[i][j];
    61         }
    62     }
    63     for(int i = 1; i <= m; i++)
    64     {
    65         cin >> a >> b;
    66         step = 1;
    67         bfs();
    68         cout << step << endl;
    69         memset(vis, 0, sizeof(vis));
    70     }
    71     return 0;
    72 }

    裸的BFS并没有什么技巧,只是注意q队列不要太小,太小会导致WA。这个代码会有3个测试点TLE。

     之所以会出现TLE,主要是有很多次询问,每次询问都做了一次BFS,要优化代码就要减少BFS的次数。注意到这样一个事实:如果迷宫中存在连通块,则连通块中各格子到其他格子的个数是相同的。而求连通块本身就是利用BFS实现的。下面就是利用连通块进行优化的代码。

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <math.h>
     4 #include <algorithm>
     5 #include <string.h>
     6 
     7 using namespace std;
     8 
     9 struct Node
    10 {
    11     int x, y;
    12 };
    13 Node q[1000005];
    14 int cnt[1000005];
    15 
    16 const int MAXN = 1005;
    17 int n, m, a, b, c, d, front, last, step, num; 
    18 int pos[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
    19 char abc[MAXN][MAXN]; // 存储输入的矩阵信息 
    20 bool vis[MAXN][MAXN]; // 是否已经遍历过该点
    21 int map[MAXN][MAXN]; // 用于对连通块染色 
    22 
    23 
    24 void bfs()
    25 {
    26     Node now, next;
    27     now.x = a;
    28     now.y = b;
    29     map[a][b] = num;
    30     vis[a][b] = 1;
    31     step = 1;
    32     
    33     front = last = 0;
    34     q[last] = now;
    35     last++;
    36     while(front < last)
    37     {
    38         now = q[front++];
    39         for(int i = 0; i < 4; i++)
    40         {
    41             int nx = now.x + pos[i][0]; 
    42             int ny = now.y + pos[i][1]; 
    43             if(nx <= n && nx > 0 && ny <= n && ny > 0 
    44                 && vis[nx][ny] == false 
    45                 && abc[now.x][now.y] != abc[nx][ny]) 
    46             {
    47                 vis[nx][ny] = true;
    48                 q[last].x = nx;
    49                 q[last].y = ny;
    50                 map[nx][ny] = num;
    51                 step++;
    52                 last++;
    53             }
    54         } 
    55     }
    56     cnt[num] = step;
    57     num++;
    58 }
    59 
    60 int main()
    61 {
    62     cin >> n >> m;
    63     for(int i = 1; i <= n; i++)
    64     {
    65         for(int j = 1; j <= n; j++)
    66         {
    67             cin >> abc[i][j];
    68         }
    69     }
    70     num = 1;
    71     for(int i = 1; i <= m; i++)
    72     {
    73         cin >> a >> b;
    74         if(map[a][b] == 0) 
    75         {
    76             bfs();            
    77         }    
    78         cout << cnt[map[a][b]] << endl;
    79     }
    80     return 0;
    81 }

    其中的map数组是用来存储连通块的染色信息的。如果格子对应的map数据为0,说明没有做过BFS。cnt数组存储着每个连通块所对应的格子个数。经过这次优化,就可以AC了。

  • 相关阅读:
    devstack安装openstack
    Stacks of Flapjacks
    二、Reids基础命令--字符串
    数据库筛选用户,然后去掉一部分(列表求差),再随机返回一个用户。sqlalchemy + python集合(set) + random
    利用Powershell获取公司内部机器的资源信息,作为企业兴许资产管理的基本途径!
    《编程导论(Java)&#183;3.2.4 循环语句》
    Android自己主动检測版本号及自己主动升级
    基于bootstrap的富文本框——wangEditor【欢迎增加开发】
    找球号(三)
    #308 (div.2) B. Vanya and Books
  • 原文地址:https://www.cnblogs.com/zealsoft/p/11327497.html
Copyright © 2011-2022 走看看