计蒜客题解——T1769:合租

题目相关

题目链接

计蒜客,https://nanti.jisuanke.com/t/T1769

我的OJ,http://47.110.135.197/problem.php?id=5253

题目描述

蒜头君来到一座陌生的城市打工,他和几个朋友合租一个房子。房东给他们发来了户型图,这个房子非常大,而且布局很奇怪。具体来说,房子可以被看做一个 N×M 的矩形,有墙壁的地方被标记为'#',其他地方被标记为'.'。通过'.'连在一起的区域被称作房间,现在蒜头君想知道,一共有多少个房间。

输入格式

第一行包含两个整数,N 和 M。

接下来 N 行,每行包含 M 个字符描述房间的情况,只包含'#''.'

输出格式

输出一个整数,表示房间的个数。

输入样例

3 3
#.#
#.#
.#.

输出样例

3

题目分析

题意分析

在一个 N×M 的矩形找出连通区域有几块。标准的 BFS 题目。

P.S.

本题是一个判断连通性问题,也可以使用查并集来解决。

样例数据分析

没什么特别需要分析的,套用 BFS 模板就可以了。

数据范围分析

鄙视一下出题人,没有给出明确的 N 和 M 的范围,搞得我 n+1 次段错误,最后经过测试得到 N, M ≤ 2000。

算法思路

核心就是从头到尾遍历矩阵,如果某个位置 (x,y),如果该点为 . ,而且没有被访问过,就以该点为起点进行一次 BFS,搜索完成房间数加一。一直到整个矩阵遍历完成。

这样的算法复杂度为 O(n^{2})。根据最不利原则,在最坏的情况下,矩阵一半的房间,一半是墙壁,而且每个房间只有一个点。如下数据样例:

6 6
. # . # . #
# . # . # .
. # . # . #
# . # . # .
. # . # . #
# . # . # .

也就是说,最大的处理数据量为 2000*2000/2=2e6 的数据。

当前这个暴力搜索算法在计蒜客已经通过。

参考代码

暴力搜索代码

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 2002;
const int MAXM = MAXN;

typedef struct _POS {
    int x;
    int y;
} POS;

typedef struct _ROOM {
    int n;
    int m;
    char data[MAXN][MAXM];
    bool vis[MAXN][MAXM];
} ROOM;

void bfs(ROOM &room, int x, int y) {
    queue<POS> q;
    POS cur = {x,y};
    q.push(cur);
    room.vis[cur.x][cur.y]=true;

    POS next;
    const POS moves[] = {{0,-1}, {1,0}, {0,1}, {-1,0}};

    while (false==q.empty()) {
        cur = q.front();
        q.pop();

        for (int i=0; i<4; i++) {
            next.x = cur.x+moves[i].x;
            next.y = cur.y+moves[i].y;

            if (next.x>=0&&next.x<room.n
                &&next.y>=0&&next.y<room.m
                &&'.'==room.data[next.x][next.y]
                &&false==room.vis[next.x][next.y]) {
                room.vis[next.x][next.y]=true;
                q.push(next);
            }
        }
    }
}

int main() {
    ROOM room = {};
    cin>>room.n>>room.m;

    for (int i=0; i<room.n; i++) {
        for (int j=0; j<room.m; j++) {
            cin>>room.data[i][j];
        }
    }

    int ans=0;
    for (int i=0; i<room.n; i++) {
        for (int j=0; j<room.m; j++) {
            if ('.'==room.data[i][j] && false==room.vis[i][j]) {
                //房间
                bfs(room, i, j);
                ans++;
            }
        }
    }

    cout<<ans<<endl;

    return 0;
}

剪枝优化算法

就是在暴力搜索的基础上,对代码进行优化。我们可以看到最核心代码是 n*m 这个暴力搜索。如果我们将所有的房间保存起来,然后搜索范围放在保存的队列里。这样的方法不是降低算法时间复杂度,只是降低搜索的次数,剪枝技巧罢了。

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

const int MAXN = 2e3+4;
const int MAXM = 2e3+4;

typedef struct _POS {
    int x;
    int y;
} POS;

typedef struct _ROOM {
    int n;
    int m;
    char data[MAXN][MAXM];
    bool vis[MAXN][MAXM];
} ROOM;

vector<POS> myvect;

void bfs(ROOM &room, const POS &pos) {
    queue<POS> q;
    q.push(pos);
    room.vis[pos.x][pos.y]=true;

    const POS moves[] = {{0,-1}, {1,0}, {0,1}, {-1,0}};
    POS cur;
    POS next;

    while (false==q.empty()) {
        cur = q.front();
        q.pop();

        for (int i=0; i<4; i++) {
            next.x = cur.x+moves[i].x;
            next.y = cur.y+moves[i].y;

            if (next.x>=0&&next.x<room.n
                &&next.y>=0&&next.y<room.m
                &&'.'==room.data[next.x][next.y]
                &&false==room.vis[next.x][next.y]) {
                room.vis[next.x][next.y]=true;
                q.push(next);
            }
        }
    }
}

int main() {
    ROOM room = {};
    cin>>room.n>>room.m;

    char data;
    for (int i=0; i<room.n; i++) {
        for (int j=0; j<room.m; j++) {
            cin>>room.data[i][j];
            if ('.'==room.data[i][j]) {
                POS pos = {i,j};
                myvect.push_back(pos);
            }
        }
    }

    int ans=0;
    vector<POS>::iterator it;
    for (it=myvect.begin(); it<myvect.end(); it++) {
        POS pos = *it;
        if (false==room.vis[pos.x][pos.y]) {
            bfs(room, pos);
            ans++;
        }
    }

    cout<<ans<<endl;

    return 0;
}
发布了235 篇原创文章 · 获赞 289 · 访问量 107万+

猜你喜欢

转载自blog.csdn.net/justidle/article/details/104855000