藍橋杯——全球變暖
阿新 • • 發佈:2019-01-04
標題:全球變暖
你有一張某海域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;
}
}