洛谷P1331 海战(DFS)

题目背景

在峰会期间,武装部队得处于高度戒备。警察将监视每一条大街,军队将保卫建筑物,领空将布满了 F-2003 飞机。

此外,巡洋船只和舰队将被派去保护海岸线。不幸的是,因为种种原因,国防海军部仅有很少的几位军官能指挥大型海战。因此,他们培养了一些新海军指挥官。军官们选择了“海战”游戏来帮助他们学习。

 题目描述

在一个方形的盘上,放置了固定数量和形状的船只,每只船却不能碰到其它的船。在本题中,我们认为船是方形的,所有的船只都是由图形组成的方形。

求出该棋盘上放置的船只的总数。

 输入格式

第一行为两个整数 R 和 C,用空格隔开,分别表示游戏棋盘的行数和列数。

接下来 R 行,每行 C个字符,为 # 或 .  。# 表示船只的一部分,. 表示水。

 输出格式

一行一个字符串,如果船的位置放得正确(即棋盘上只存在相互之间不能接触的方形,如果两个 # 号上下相邻或左右相邻却分属两艘不同的船只,则称这两艘船相互接触了)。就输出 There are S shipsS表示船只的数量。否则输出 Bad placement.(注意,有句点!)。

 样例输入 #1
 6 8
 .....#.#
 ##.....#
 ##.....#
 .......#
 #......#
 #..#...#

 样例输出 #1
 There are 5 ships.

 提示

对于 100% 的数据,1≤R,C≤1000。

思路

题目相信大家都看明白了吧,很显然,这是一个深度优先搜索题目哈,也就是说对于每一个“."(没有遍历过的)我们进行一次搜索,找到它的四连通块也就是船,定义cnt来统计船的数目,这个相信大家都知道,但此题的难点在于所谓的Bad placement.那么要如何判断Bad placement.呢?我们通过模拟可知对于每一个不合格的矩形,它一定有如下四种结构:

第一种

##

#.

第二种

##

.#

第三种

.#

##

第四种

#.

##

显而易见的,对于每一个2x2的不合法方块,都一定有3个#号和一个 . 号(可以理解吧)

所以我们只需要在一次正式的搜索前面,对每一个2x2的方块进行一次搜索,判断是否有不合法方块,有的话直接输出 Bad placement. 代码结束,return 0;

否则进行下面的搜索,搜索还简单的吧,那么代码如下。

代码

/*对于一个不合法的方块,一定会有如下的状况
##  ##  .#  #.
#.  .#  ##  ##
也就是说对于一个2x2的方块一旦有3个#号和一个.号
*/
#include<iostream>
using namespace std;
const int N = 1005;
char x[N][N];
int a[N][N];
int vis[N][N];
int dir[4][2] = { {1,0},{-1,0},{0,-1},{0,1} };
int r, c;
int tmp = 0;
int cnt;
void dfs(int x, int y)
{
	for (int i = 0; i < 4; i++)
	{
		int nx = x + dir[i][0];
		int ny = y + dir[i][1];
		if (nx >= 1 && nx <= r && ny >= 1 && ny <= c && a[nx][ny] == 1 && vis[nx][ny] == 0)
		{
			tmp += 1;
			vis[nx][ny] = tmp;
			dfs(nx, ny);
		}
	}
	return;
}
int main()
{
	cin >> r >> c;
	for (int i = 1; i <= r; i++)
	{
		for (int j = 1; j <= c; j++)
		{
			cin >> x[i][j];
			if (x[i][j] == '#')
			{
				a[i][j] = 1;
			}
			if (x[i][j] == '.')
			{
				a[i][j] = 0;
			}
		}
	}
	int tmp_1 = 0,tmp_2=0;
	for (int i = 1; i <= r; i++)
	{
		for (int j = 1; j <= c; j++)
		{
			if (a[i][j] == 1)
			{
				tmp_1++;
			}
			if (a[i][j+1] == 1)
			{
				tmp_1++;
			}
			if (a[i+1][j] == 1)
			{
				tmp_1++;
			}
			if (a[i+1][j+1] == 1)
			{
				tmp_1++;
			}
			if (a[i][j] == 0)
			{
				tmp_2++;
			}
			if (a[i][j + 1] == 0)
			{
				tmp_2++;
			}
			if (a[i + 1][j] == 0)
			{
				tmp_2++;
			}
			if (a[i + 1][j + 1] == 0)
			{
				tmp_2++;
			}
			if (tmp_2 == 1 && tmp_1 == 3)
			{
				cout << "Bad placement." << endl;
				return 0;
			}
			tmp_1 = 0;
			tmp_2 = 0;//初始化以便下次使用!
		}
	}
	for (int i = 1; i <= r; i++)
	{
		for (int j = 1; j <= c; j++)
		{
			if (a[i][j] == 1 && vis[i][j] == 0)
			{
				dfs(i, j);
				cnt++;
			}
		}
	}
	cout << "There are " << cnt << " ships.";
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值