标题:全球变暖
你有一张某海域NxN像素的照片,"."表示海洋、"#"表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
【输入样例】
7
.......
.##....
.##....
....##.
..####.
...###.
.......
【输出样例】
你有一张某海域NxN像素的照片,"."表示海洋、"#"表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。
照片保证第1行、第1列、第N行、第N列的像素都是海洋。
【输出格式】
一个整数表示答案。【输入样例】
7
.......
.##....
.##....
....##.
..####.
...###.
.......
【输出样例】
1
思路:dfs判断,最后处理岛的个数。
7
.......
..###..
..###..
..###..
..###..
..##...
.......
0
7
.......
..###..
..###..
..##...
..###..
..##...
.......
0
看成了求淹没后剩下的岛的数量,而题中要求的是“被淹没岛的数量”
这个代码是求剩下的岛的数量:
import java.util.Scanner;
public class 全球变暖 {
/**
* 题中说:照片保证第1行、第1列、第N行、第N列的像素都是海洋
* 所以判断条件会简单很多
* @param args
*/
static int sum=0;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m[][]=new int[n][n];
//将‘.’变为0,‘#’变为1(个人习惯,其实都一样)
for (int i = 0; i < m.length; i++) {
String s=sc.next();
for (int k = 0; k < s.length(); k++) {
if(s.charAt(k)=='.'){
m[i][k]=0;
}else {
m[i][k]=1;
}
}
}
int vis[][]=new int[n][n];
dfs(m,vis,0,0);
int res=judge(vis,sum);
System.out.println(res);
}
/**
* 判断最终的岛屿数量
* @param vis 水淹没之后的岛屿地图
* @param s 现在的岛屿由几个‘#’组成
* @return
*/
private static int judge(int[][] vis, int s) {
int t=s;
for (int i = 0; i < vis.length; i++) {
for (int j = 0; j < vis[0].length; j++) {
if(vis[i][j]==1){
vis[i][j]=2;
if(vis[i+1][j]==1){
t--;
}else if (vis[i-1][j]==1) {
t--;
}else if (vis[i][j-1]==1) {
t--;
}else if (vis[i][j+1]==1) {
t--;
}
}
}
}
return t;
}
/**
* dfs水淹
* @param m 初始地图
* @param vis 记忆表
* @param h 行
* @param l 列
*/
private static void dfs(int[][] m, int[][] vis, int h, int l) {
if(h==m.length){
return;
}
if(m[h][l]==0){
dfs(m,vis, h+(l+1)/m.length,(l+1)%m.length);
}else {
if(m[h][l]==1 && check(m,h,l)){
sum++;
vis[h][l]=1;
dfs(m,vis, h+(l+1)/m.length,(l+1)%m.length);
}else {
dfs(m,vis, h+(l+1)/m.length,(l+1)%m.length);
}
}
}
/**
* 判断是否被水淹
* @param m
* @param h
* @param l
* @return
*/
private static boolean check(int[][] m, int h, int l) {
if(m[h+1][l]==1 && m[h-1][l]==1 && m[h][l+1]==1 && m[h][l-1]==1){
return true;
}
return false;
}
}
正确代码,被淹的岛的数量
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
public class 全球变暖_bfs {
/**
* 基本是通过遍历,找到一个岛屿的开始,然后遍历整座岛屿,用vis数组加以区分
* 一次bfs遍历完成退出while循环 一座岛屿就遍历完成
* 编号自增,
* 根据vis[i][j]=0&&x[i][j]=1找下一个岛屿
* 最后list记录了所有岛屿的坐标及其属于的岛的编号sign
* 只需要根据vis数组找到,上下左右都是“#”的地方,然后根据编号判断被淹没的岛的数量
* @param args
*/
static class node{
public int x;
public int y;
public int sign;//岛屿的编号
node(int x,int y,int sign){
this.x=x;
this.y=y;
this.sign=sign;
}
}
static int num=0;//岛的总数
static LinkedList<node> list=new LinkedList<node>();
static int dir[][]={{-1,0},{0,1},{1,0},{0,-1}};
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int x[][]=new int[n][n];
for (int i = 0; i < n; i++) {
String s=sc.next();
for (int j = 0; j < s.length(); j++) {
if(s.charAt(j)=='#'){
x[i][j]=1;
}
}
}
int vis[][]=new int[n][n];
for (int i = 1; i < x.length; i++) {
for (int j = 1; j < x[0].length; j++) {
if(x[i][j]==1){//说明是陆地
if(vis[i][j]==0){//没有被访问过
num++;
list.add(new node(i,j,num));//记录岛组成
//bfs遍历这个岛并记录这个岛的编号
bfs(x,vis);//bfs过程中会更新vis表
}
}
}
}
Set<Integer> res=new HashSet<Integer>();//记录被淹没的到的编号
for (int i = 0; i < list.size(); i++) {
int xe=list.get(i).x;
int ye=list.get(i).y;
// System.out.println(xe+" "+ye+" "+list.get(i).sign);
//周围是“#”说明没有被淹没
if(vis[xe+1][ye]==2&&vis[xe-1][ye]==2&&vis[xe][ye+1]==2&&vis[xe][ye-1]==2){
// System.out.println(xe+" x "+ye+" "+list.get(i).sign);
res.add(list.get(i).sign);
}
}
int sum=0;//被淹岛的数量
for (int i = 1; i <= num; i++) {
if(!res.contains(i)){
sum++;
}
}
System.out.println("幸存的岛屿编号"+res);//最后幸存的岛的编号
System.out.println("被淹的岛数"+sum);
}
private static void bfs(int[][] x, int[][] vis) {
Queue<node> q=new LinkedList<node>();
q.offer(list.getLast());
while (q.size()!=0) {
node temp=q.poll();
//这里要区分没被遍历过的地方,海,和陆地
if(x[temp.x][temp.y]==0){//判断这个节点是海还是陆地
vis[temp.x][temp.y]=1;//海标1
}else {
vis[temp.x][temp.y]=2;//陆地标2
}
//遍历周围节点
for (int k = 0; k < dir.length; k++) {
int xt=temp.x+dir[k][0];
int yt=temp.y+dir[k][1];
//如果这个点在范围内且不是海洋
if(in(x,xt,yt) && vis[xt][yt]!=1){
//如果没被遍历过且是岛屿
if(vis[xt][yt]==0 && x[xt][yt]==1){
q.offer(new node(xt,yt,temp.sign));
}
list.add(temp);
}
}
}
}
private static boolean in(int[][] m, int x, int y) {
if(x<=0 || x>=m.length-1 || y<=0 || y>=m[0].length-1){
return false;
}
return true;
}
}