第九届蓝桥杯省赛(9) -- 全球变暖

一.题目
标题:全球变暖

你有一张某海域NxN像素的照片,"."表示海洋、"#"表示陆地,如下所示:

.......
.##....
.##....
....##.
..####.
...###.
.......

其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。  

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。  

例如上图中的海域未来会变成如下样子:

.......
.......
.......
.......
....#..
.......
.......

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。  

【输入格式】
第一行包含一个整数N。  (1 <= N <= 1000)  
以下N行N列代表一张海域照片。  

照片保证第1行、第1列、第N行、第N列的像素都是海洋。  

【输出格式】
一个整数表示答案。

【输入样例】

.......
.##....
.##....
....##.
..####.
...###.
.......  

【输出样例】
1  

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 1000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include <xxx>
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

二.思路 

主要运用bfs,广度搜索,遍历两次。第一次遍历,给周围有水域的坐标点,标记访问矩阵vis[i][j],该点值为2。

再从头遍历vis[i][j],使图Map[i][j]对应的vis[i][j]=2的点变为'.'(水域)。再进行第二次遍历,这边我看了许多博客,我认为大部分的解法都是存在的问题,不能简单的将两次遍历的数量相减,若小于0,则为0。问题出在,有的陆地可能会分成两个陆地,若同时有一个陆地消失,减下来的结果是没有陆地消失,根据题意显然是不对的,上述情况应该有一个陆地消失。我的解法是,在第一遍遍历的时候给节点标上序号,在第二遍遍历前创建为序号大小的数组,其值全为1,在第二遍遍历的时候,算法中不再改变节点的序号值,遇到序号则把数组中对应位置置0,最后遍历该数组,1的个数即为消失的陆地数

三.源码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct Node{
  	int x,y; //坐标 
  	int num; //第几号陆地,第一个陆地的序号为0 
}Now,Next,S;
char MAP[1005][1005];
int vis[1005][1005];
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int n,sum;

bool in(int x,int y){
  	if(x >= 0 && y >= 0 && x < n && y < n)	return true;
  	return false;
}

// 如果周围有水,返回真 
bool Check(int x,int y){
	for(int i=0;i<4;i++){
    	int X = x + dir[i][0];
    	int Y = y + dir[i][1];
    	if(MAP[X][Y] == '.' && in(X,Y))  	return true;
  	}
  	return false;
}

void bfs(){
	queue<Node> q;
  	S.num = sum;
  	q.push(S);
  	while(!q.empty()){
		Now = q.front();
    	q.pop();
    	if(Check(Now.x,Now.y)){
      		vis[Now.x][Now.y] = 2;
    	}else
    	{
    		vis[Now.x][Now.y] = 1;
    	}
    	for(int i=0;i<4;i++){
      		Next.x = Now.x + dir[i][0];
      		Next.y = Now.y + dir[i][1];
      		if(in(Next.x,Next.y) && MAP[Next.x][Next.y] == '#' && vis[Next.x][Next.y] == 0){
    			Next.num = Now.num;
        		q.push(Next);
      		}
    	}
  	}
  	sum++;
  	return ;
}
// bfs2 的作用于bfs 是基本一致的,不同的在于遍历的过程中不改变节点的num属性 
void bfs2(){
	queue<Node> q;
  	q.push(S);
  	while(!q.empty()){
		Now = q.front();
    	q.pop();
    	if(Check(Now.x,Now.y)){
      		vis[Now.x][Now.y] = 2;
      		Map[Now.x][Now.y] = '.';
    	}else
    	{
    		vis[Now.x][Now.y] = 1;
    	}
    	for(int i=0;i<4;i++){
      		Next.x = Now.x + dir[i][0];
      		Next.y = Now.y + dir[i][1];
      		if(in(Next.x,Next.y) && MAP[Next.x][Next.y] == '#' && vis[Next.x][Next.y] == 0){
    			q.push(Next);
      		}
    	}
  	}
  	return ;
}

int main()
{
  	scanf("%d",&n);
  	for(int i=0;i<n;i++){
    	scanf("%s",MAP[i]);
  	}
  	memset(vis,0,sizeof(vis));
  	sum = 0;
  	for(int i=0;i<n;i++){
    	for(int j=0;j<n;j++){
      		if(MAP[i][j] == '#'){
        		if(vis[i][j] != 0)continue;
        		S.x = i;
        		S.y = j;
        		bfs();
      		}
    	}
  	}
  	int num_old = sum;
  	for (int i=0;i<n;i++) {
  		for (int j=0;j<n;j++) {
  			if(vis[i][j]==2) {
  				MAP[i][j]='.';
  			}
  		}
  	}
  	int a[num_old];
  	for(int i=0;i<num_old;i++) {
  		a[i] =1;
  	}
  	sum = 0;
  	
  	memset(vis,0,sizeof(vis));
  	for(int i=0;i<n;i++){
    	for(int j=0;j<n;j++){
      		if(MAP[i][j] == '#'){
        		if(vis[i][j] != 0) continue;
        		a[S.num] = 0;
        		S.x = i;
        		S.y = j;
        		bfs();
      		}
    	}
  	}
	int answer=0;
	for(int i=0;i<num_old;i++) {
		if(a[i]==1)
		answer++;
	}
	printf("%d",answer);
  	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值