https://www.acmicpc.net/problem/16932
16932번: 모양 만들기
N×M인 배열에서 모양을 찾으려고 한다. 배열의 각 칸에는 0과 1 중의 하나가 들어있다. 두 칸이 서로 변을 공유할때, 두 칸을 인접하다고 한다. 1이 들어 있는 인접한 칸끼리 연결했을 때, 각각의
www.acmicpc.net
문제풀이
처음에는 일반적인 BFS문제인줄 알았습니다.
문제 조건에
- 2 ≤ N, M ≤ 1,000
를 보면 1000 x 1000 x 1000 x 1000 = 1,000,000,000,000 ( 1조의 계산결과?? )
(가로x세로)x(BFS들어갔을때 연산으로 최대 1000번 x 1000) 의 최악의 결과가 있습니다.
시간초과를 위해서는
각 Group을 Indexing 시켜서 진행합니다. 즉, Grouping 시킵니다.
시간초과를 해결하기 위하여 예시입력입니다.
3 3 0 1 1 0 0 1 0 1 0
Grouping을 통하여 index를 매겨주면 아래의 그림처럼 Map을 변경시켜줍니다.
0 2 2 0 0 2 0 3 0
이렇게 됩니다.
indexKey를 2부터 시작하는 이유는 Map이 1인경우와 구분하여 Visited 처리를 동시에 진행하기 위하여입니다.
현재로써는 이해가 안되시겠지만, 코드를 보면 이해가 되실 것 입니다.
또한 에러가 있어서 시간을 잡아먹힌 부분은,
아래의 getByIndex에서 HashMap을 활용하여 진행할떄 HashMap에 값이 없으면 NULL이 나옵니다.
그러므로 map[nx][ny] = 0 일경우 continue 조건을 넣음으로써 반드시 Grouping한 값을 Key로써 넣어주어야 sizeTemp에 Size를 더하는 코드에서 NULLPOINTERException 에러가 나지 않습니다.
public static void getByIndex(int startx, int starty) { HashSet<Integer> visitedHashSet = new HashSet<>(); for(int dir=0;dir<4;dir++) { int nx = startx + dx[dir]; int ny = starty + dy[dir]; if(nx < 0 || nx >= N || ny < 0 || ny >= M) continue; if(map[nx][ny] == 0) continue; if(visitedHashSet.contains(map[nx][ny])) continue; //방문처리 visitedHashSet.add(map[nx][ny]); //해당 index의 Size값을 더함 sizetemp += indexHasmmap.get(map[nx][ny]); } }
코드
처음에 시간초과 코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; public class Main { public static int N,M; public static int[][] map; public static Queue<Node> q = new LinkedList<>(); public static boolean[][] visited; public static int result = 0; public static int realresult = 0; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); map = new int[N][M]; for(int i=0;i<N;i++) { st = new StringTokenizer(br.readLine()); for(int j=0;j<M;j++) { map[i][j] = Integer.parseInt(st.nextToken()); } } for(int i=0;i<N;i++) { for(int j=0;j<M;j++) { visited = new boolean[N][M]; if(map[i][j] == 0) { //1로 변경 map[i][j] = 1; result = 1; Simulate(i, j); realresult = Math.max(realresult, result); map[i][j] = 0; //다시 0으로 초기화 } } } System.out.println(realresult); } public static void Simulate(int startx, int starty) { int[] dx = {-1,1,0,0}; int[] dy = {0,0,-1,1}; q.offer(new Node(startx, starty, 1)); visited[startx][starty] = true; while(!q.isEmpty()) { Node temp = q.poll(); int x= temp.x; int y = temp.y; int cnt = temp.cnt; for(int dir=0;dir<4;dir++) { int nx = x + dx[dir]; int ny = y + dy[dir]; if(nx < 0 || nx >= N || ny < 0 || ny >= M) continue; if(visited[nx][ny] == true || map[nx][ny] == 0) continue; q.offer(new Node(nx, ny, cnt + 1)); visited[nx][ny] = true; result+=1; } } } } class Node{ int x; int y; int cnt; public Node(int x, int y, int cnt) { this.x=x; this.y=y; this.cnt = cnt; } }
각 그룹을 Grouping 하여 해결한 코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; public class Main { public static int N,M; public static int[][] map; public static int[] dx = {-1,1,0,0}; public static int[] dy = {0,0,-1,1}; public static HashMap<Integer, Integer> indexHasmmap = new HashMap<>(); public static ArrayList<Node> zeroArr = new ArrayList<>(); public static int indexKey=2; public static int sizetemp = 0; public static int result = 0; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); map = new int[N][M]; for(int i=0;i<N;i++) { st = new StringTokenizer(br.readLine()); for(int j=0;j<M;j++) { map[i][j] = Integer.parseInt(st.nextToken()); if(map[i][j] == 0) zeroArr.add(new Node(i,j)); } } for(int i=0;i<N;i++) { for(int j=0;j<M;j++) { if(map[i][j] == 1) { makeIndex(i, j); } } } for(int i=0;i<zeroArr.size();i++) { sizetemp = 1; getByIndex(zeroArr.get(i).x, zeroArr.get(i).y); result = Math.max(result, sizetemp); } System.out.println(result); } public static void getByIndex(int startx, int starty) { HashSet<Integer> visitedHashSet = new HashSet<>(); for(int dir=0;dir<4;dir++) { int nx = startx + dx[dir]; int ny = starty + dy[dir]; if(nx < 0 || nx >= N || ny < 0 || ny >= M) continue; if(map[nx][ny] == 0) continue; if(visitedHashSet.contains(map[nx][ny])) continue; //방문처리 visitedHashSet.add(map[nx][ny]); //해당 index의 Size값을 더함 sizetemp += indexHasmmap.get(map[nx][ny]); } } public static void makeIndex(int startx, int starty) { Queue<Node> q = new LinkedList<>(); q.offer(new Node(startx, starty)); map[startx][starty] = indexKey; int indexSize = 1; while(!q.isEmpty()) { Node temp = q.poll(); int x = temp.x; int y = temp.y; for(int dir=0;dir<4;dir++) { int nx = x + dx[dir]; int ny = y + dy[dir]; if(nx < 0 || nx >= N || ny < 0 || ny >= M ) continue; if(map[nx][ny] != 1) continue; q.offer(new Node(nx, ny)); map[nx][ny] = indexKey; indexSize += 1; } } indexHasmmap.put(indexKey, indexSize); indexKey+=1; } } class Node{ int x; int y; public Node(int x, int y) { this.x=x; this.y=y; } }
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 22868 산책 (small) - BFS + 아이디어 + 시간초과 JAVA (0) | 2023.07.06 |
---|---|
[백준] 9466 텀 프로젝트 - DFS + 아이디어 + 시간초과 JAVA (0) | 2023.07.06 |
[백준] 2206 벽 부수고 이동하기 - BFS + 아이디어 JAVA (0) | 2023.07.04 |
[백준] 16954 움직이는 미로 탈출 - BFS JAVA (0) | 2023.07.03 |
[백준] 1600 말이 되고픈 원숭이 - BFS JAVA (0) | 2023.07.02 |