【C++/DFS连通块】海战

136 阅读2分钟

海战

题目描述

在峰会期间,武装部队得处于高度戒备。警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机。此外,巡洋船只和舰队将被派去保护海岸线。不幸的是因为种种原因,国防海军部仅有很少的几位军官能指挥大型海战。因此,他们考虑培养一些新的海军指挥官,他们选择了“海战”游戏来帮助学习。

在这个著名的游戏中,在一个方形的盘上放置了固定数量和形状的船只,每只船却不能碰到其它的船。在这个题中,我们仅考虑船是方形的,所有的船只都是由图形组成的方形。编写程序求出该棋盘上放置的船只的总数。

输入格式

输入文件头一行由用空格隔开的两个整数R和C组成,1<=R,C<=1000,这两个数分别表示游戏棋盘的行数和列数。接下来的R行每行包含C个字符,每个字符可以为“#”,也可为“.”,“#”表示船只的一部分,“.”表示水。

输出格式

为每一个段落输出一行解。如果船的位置放得正确(即棋盘上只存在相互之间不能接触的方形,如果两个“#”号上下相邻或左右相邻却分属两艘不同的船只,则称这两艘船相互接触了)。就输出一段话“There are S ships.”,S表示船只的数量。否则输出“Bad placement.”。

样例 #1

样例输入 #1

6 8
.....#.#
##.....#
##.....#
.......#
#......#
#..#...#

样例输出 #1

There are 5 ships.

思路

可以用DFS搜索地图每一个地方,如果不是‘#’就跳过,如果是‘#’,就开始逐步深搜。在搜索前可以判断一下已经输出的地图里面的船是否存在放的不正确的地方,也就是说是否有不是矩形的船。

image.png

从上图可以得知,遍历地图所有元素的时候,可以判断以mp[i][j]为左上角的2 * 2矩形中含有的‘#’数量是否为3,为3说明该‘#’区域不满足矩形的条件,直接输出 Bad Placement. 并返回。如果满足就继续进行下面的搜索,搜索与简单的连通块一致。

AC代码

#include<bits/stdc++.h>
#define ts ios::sync_with_stdio (false);cin.tie(0);
using namespace std;

int ct=0; //连通块数量
int n,m;
int vis[1005][1005]={0}; //标记数组
char mp[1005][1005]; //地图
int dir[][2]={
        {0,1},{0,-1},{1,0},{-1,0}
};

void dfs(int x,int y)
{
    if(x<0||x>n-1||y<0||y>m-1) //是否出界
        return;
    if(mp[x][y]!='#'||vis[x][y]) //是否有搜索的必要 以及 该点是否以及搜索过了
        return;
    vis[x][y]=1; //未搜索过就标记
    for(int i=0;i<4;i++)
    {
        dfs(x+dir[i][0],y+dir[i][1]);
    }
}

int main()
{
    ts;

    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>mp[i][j];
        }
    }
    for(int i=0;i<n;i++)  //判断地图中是否有不规则的‘#’区域
    {
        for(int j=0;j<m;j++)
        {
            int sum=0;
            if(i<0||i>n-1||j<0||j>m-1) //点不合法就下一个
                continue;
            if(mp[i][j]=='#') sum++;
            if(mp[i+1][j]=='#') sum++;
            if(mp[i][j+1]=='#') sum++;
            if(mp[i+1][j+1]=='#') sum++;
            if(sum==3)
            {
                cout<<"Bad placement.";
                return 0;
            }

        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(vis[i][j]==0&&mp[i][j]=='#') //未搜索过 且 该点为‘#’说明该点是新的一个连通块
            {
                ct++;
                dfs(i,j); //开始从此点开搜

            }

        }
    }
    cout<<"There are "<<ct<<" ships.";

    return 0;
}

//2022.5.23