题解 U23217 【yizimi数字岛屿探险】

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

题目

题目背景

yizimi的宝藏是数学的奥秘……

(待完善正解,将来可能会SPJ)

题目描述

yizimi在一个岛上降落,他有一个遥感器,显示他所在的坐标x,y,显示了n * m的地图:地图上显示0,则此坐标位置为海洋,地图上显示1~9,则为海拔为显示数字的陆地。

yizimi发现周围有许多岛屿,包括他自己所在的岛屿,不过他去不了除自己所在岛屿以外的地方。他要寻求的宝藏是他可以去到的所有坐标位置的海拔的乘积,取模100007。

不过他还想知道他所在的岛屿的面积与所给地图的中有几个岛屿。

输入输出格式

输入格式:

第1行:n,m 地图行数列数

第2~n+1行:为m个用空格隔开的数字,代表各地海拔。

第n+2行:x,y yizimi所在第x行,第y列

输出格式:

第一行:所在岛屿面积(每个点3分)

第二行:岛屿个数(每个点3分)

第三行:yizimi的数字宝藏(每个点4分)

说明

对于100%的数据:2<=n,m<=1000

保证yizimi跳伞不会跳到海里去

题目分析

首先,要注意这道题

有三问!!!!!!

第一问是一道很简单的连通块的问题,通过DFS。

第二问是一个关于染色的问题,要染几种颜色才能染完除0外的所有点。

第三问是第一问的升级版,只是把计数变为了数字乘积而已。

所以,此题的重点就是在搜索上。

本道题DFS与BFS都适用。本体街使用的是DFS。

具体实现

求简单的连通块

这个说实话不用多讲,用DFS,枚举每一个方向的可行性,进行下一步扩展,在扩展过程中标记、计数、计算乘积。

inline void dfs1(int x,int y){
	for(int i=1;i<=4;i++){
    	int nx=x+dx[i],ny=y+dy[i];
		if(nx>n || nx<1 || ny>m || ny<1)
			continue;
		if(a[nx][ny]>0 && !bb[nx][ny]){
			ans1++;
			ans2=(ans2*a[nx][ny])%mod;
			//cout<<ans2<<"
";
			bb[nx][ny]=true;
			dfs1(nx,ny);
		}
	}
}

求连通块的个数

就是枚举所有点所在的连通块,用一个负数标记,每次把大于0的坐标及其连通块染色,继续枚举。

枚举

	int color=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(b[i][j]>0)
				color--,bbb[i][j]=true,b[i][j]=color,dfs2(i,j,color);

染色

inline void dfs2(int x,int y,int color){
	for(int i=1;i<=4;i++){
		if(nx<=n && nx>=1 && ny<=m && ny>=1 && b[nx][ny]>0){
			b[nx][ny]=color;
			bbb[nx][ny]=true;
			dfs2(nx,ny,color);
		}
	}
}

完整代码

依然有自己的代码特点

define狂魔

中间注释是测试代码用的。

#include<bits/stdc++.h>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 1010
#define nx x+dx[i]
#define ny y+dy[i]
#define inf 1<<30
#define mod 100007
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int a[mn][mn],b[mn][mn];
bool bb[mn][mn],bbb[mn][mn];
int n,m,startx,starty,ans1,ans2;
const int dx[5]={0,0,0,-1,1};
const int dy[5]={0,-1,1,0,0};
inline void dfs1(int x,int y){
	go(i,1,4,1){
		if(nx>n || nx<1 || ny>m || ny<1)
			continue;
		if(a[nx][ny]>0 && !bb[nx][ny]){
			ans1++;
			ans2=(ans2*a[nx][ny])%mod;
			//cout<<ans2<<"
";
			bb[nx][ny]=true;
			dfs1(nx,ny);
		}
	}
}
inline void dfs2(int x,int y,int color){
	go(i,1,4,1){
		if(nx<=n && nx>=1 && ny<=m && ny>=1 && b[nx][ny]>0){
			b[nx][ny]=color;
			bbb[nx][ny]=true;
			dfs2(nx,ny,color);
		}
	}
}
int main(){
	//freopen("xiaodao001.in","r",stdin);
	//freopen("xiaodao001.out","w",stdout);
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(bb,0,sizeof(bb));
	n=read(),m=read();
	//cout<<n<<" "<<m<<"
";
	go(i,1,n,1)
		go(j,1,m,1)
			b[i][j]=a[i][j]=read();
	startx=read(),starty=read();
	/*
	cout<<n<<" "<<m<<"
";
	go(i,1,n,1){
		go(j,1,m,1)
			cout<<a[i][j]<<" ";
		cout<<"
";
	}
	cout<<startx<<" "<<starty<<"
";
	*/
	bb[startx][starty]=true; 
	ans1++,ans2=a[startx][starty];
	dfs1(startx,starty);
	int color=0;
	go(i,1,n,1)
		go(j,1,m,1)
			if(b[i][j]>0)
				color--,bbb[i][j]=true,b[i][j]=color,dfs2(i,j,color);
	cout<<ans1<<"
"<<-color<<"
"<<ans2<<"
";
	/*go(i,1,n,1){
		go(j,1,m,1)
			cout<<b[i][j]<<" ";
		cout<<"
";
	}*/
	return 0;
}
NOIP2018并不是结束,而是开始
原文地址:https://www.cnblogs.com/yizimi/p/10056220.html