1. 程式人生 > >藍橋杯——全球變暖

藍橋杯——全球變暖

標題:全球變暖

你有一張某海域NxN畫素的照片,"."表示海洋、"#"表示陸地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中"上下左右"四個方向上連在一起的一片陸地組成一座島嶼。例如上圖就有2座島嶼。  
由於全球變暖導致了海面上升,科學家預測未來幾十年,島嶼邊緣一個畫素的範圍會被海水淹沒。具體來說如果一塊陸地畫素與海洋相鄰(上下左右四個相鄰畫素中有海洋),它就會被淹沒。  

例如上圖中的海域未來會變成如下樣子:
.......

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

請你計算:依照科學家的預測,照片中有多少島嶼會被完全淹沒。  

【輸入格式】
第一行包含一個整數N。  (1 <= N <= 1000)  

以下N行N列代表一張海域照片。  

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

  【輸出格式】

一個整數表示答案。

【輸入樣例】

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

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

【輸出樣例】

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;
	}
}