zoukankan      html  css  js  c++  java
  • 洛谷 P1141【BFS】+记忆化搜索+染色

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

    题目描述

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

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

    输入格式:

    第 1 行为两个正整数n,m 。

    下面 n 行,每行 n 个字符,字符只可能是 0 或者 1 ,字符之间没有空格。

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

    输出格式:

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

    输入样例#1: 
    2 2
    01
    10
    1 1
    2 2
    
    输出样例#1:
    4
    4

    说明

    所有格子互相可达。

    对于 20% 的数据,n10 ;

    对于 40% 的数据,n50 ;

    对于 50% 的数据,m5 ;

    对于 60% 的数据,n100,m100 ;

    对于 100% 的数据,n1000,m100000 。

    解题分析:
    由于这题n的范围很大,如果直接bfs的话,可能会超时,所以要加一些优化,分析题目不难得到,每次搜索得到的联通块,它们的答案都相同,所以,一次搜索后,这个联通块中所有点的答案都已经求出来了,然后将答案保存即可

    下次如果要查询这个点的答案,直接调用即可,不用再进行重复搜索。

    #include <cstdio>
    #include <queue>
    using namespace std;
    int n,m;
    char map[1100][1100];int vis[1100][1100];
    int color; int dir[][2] = {1,0,0,1,-1,0,0,-1};
    int ans[110000];               //最多可能有1000*1000个联通块
    
    struct node
    {
        int x, y;
    };
    queue<node>q;
    
    bool juge(int x, int y)
    {
        if (x<1 || y<1 || x>n || y>n || vis[x][y])return true;
        return false;
    }
    
    void bfs(int r,int c)
    {
        node now, next;
        now.x = r; now.y = c;
        vis[r][c] = color;              //不要忘记标记起点是属于第几个联通块
        ans[color]++;
        q.push(now);
        while(!q.empty())
        {
            now = q.front();
            q.pop();
            for (int i = 0; i < 4; i++)
            {
                int xx = now.x + dir[i][0];
                int yy = now.y + dir[i][1];
                if (juge(xx, yy) || map[now.x][now.y] == map[xx][yy])continue;
                vis[xx][yy] = color; ans[color]++;          //ans记录序号为color的连通块的点的个数
                //利用vis数组巧妙的将已经搜索过得连通块进行标记
                next.x = xx, next.y = yy;
                q.push(next);
            }
        }
    }
    
    int main()
    {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%s", map[i] + 1);               //注意这里要加1,因为map是从1开始存数据的
        for (int i = 1; i <= m; i++)
        {        
            int x, y;
            scanf("%d %d", &x, &y);
            if (!vis[x][y]) {
                color = i;                     //巧妙的利用染色的思想,将一个连通块中的所有的点赋一个共同的序号
                while (!q.empty())q.pop();     //如果要进行bfs,那么要清空queue
                bfs(x, y);
            }
            printf("%d
    ", ans[vis[x][y]]);
        }
        return 0;
    }

    2018-06-01

  • 相关阅读:
    Centos7安装Docker
    [LeetCode] 651. 四键键盘 ☆☆☆(动态规划)
    一行代码就能解决的算法题
    博弈问题--石头游戏(动态规划)
    [LeetCode] 322. 零钱兑换 ☆☆☆(动态规划)
    java趣题
    [LeetCode] 516. 最长回文子序列 ☆☆☆(动态规划)
    [LeetCode] 337. 打家劫舍III ☆☆☆(动态规划)
    算法基础--贪心算法
    [LeetCode] 42. 接雨水 ☆☆☆☆☆(按列、动态规划、双指针)
  • 原文地址:https://www.cnblogs.com/00isok/p/9123003.html
Copyright © 2011-2022 走看看