알고리즘/SWEA

SWEA D4 1861 정사각형방

  • -
반응형

SWEA D4 1861 정사각형방

 

 

문제링크

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5LtJYKDzsDFAXc&categoryId=AV5LtJYKDzsDFAXc&categoryType=CODE#

* 일단 문제를 정독 하고 1시간 이상 반드시 고민이 필요합니다.

 

동영상 설명

1시간 이상 고민 했지만 아이디어가 떠오르지 않는다면 동영상에서 약간의 힌트를 얻어봅시다.

 

소스보기

동영상 설명을 보고도 전혀 구현이 안된다면 연습 부족입니다.
소스를 보고 작성해 본 후 스스로 백지 상태에서 3번 작성해 볼 의지가 있다면 소스를 살짝 보세요.

더보기
package se.code.d4;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * @author 은서파
 * @since 2020. 1. 28.
 * @see https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5LtJYKDzsDFAXc&categoryId=AV5LtJYKDzsDFAXc&categoryType=CODE#
 * @mem 30,084 kb
 * @time 229 ms
 * @caution
 *          #단순배열,
 *          [고려사항]
 *          한 방에서 연결되는 다른 방은 값의 차가 1이므로 있거나 없거나 둘 중의 하나이다.
 *          방에 대한 중복 방문이 발생할 수 있기 때문에 각 방에서 도달하는 회수를 저장해주자.
 *          [입력사항]
 *          [출력사항]
 */
public class SWEA_D4_1861_정사각형방 {
	static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
	static StringBuilder output = new StringBuilder();
	static StringTokenizer tokens;

	static int[][] deltas = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };

	static int T;
	static int N;
	static int[][] rooms;

	public static void main(String[] args) throws NumberFormatException, IOException {
		input = new BufferedReader(new StringReader(src));
		T = Integer.parseInt(input.readLine());
		for (int t = 1; t <= T; t++) {
			N = Integer.parseInt(input.readLine());
			rooms = new int[N][N];
			for (int r = 0; r < N; r++) {
				tokens = new StringTokenizer(input.readLine(), " ");
				for (int c = 0; c < N; c++) {
					rooms[r][c] = Integer.parseInt(tokens.nextToken());
				}
			}
			// 입력 완료
			//solve1(t);
			solve2(t);
			//solve3(t);
		}
		System.out.println(output);
	}

	//29,348 kb, 324 ms
	static void solve1(int t) {
		int maxStart = 0;
		int maxCnt = 0;
		for (int r = 0; r < N; r++) {
			for (int c = 0; c < N; c++) {
				int sr = r;
				int sc = c;
				boolean canGo = true;
				int moveCnt = 1;
				int moveStart = rooms[sr][sc];
				while (canGo) {
					canGo = false;
					// 4방 탐색으로 가보기.
					for (int d = 0; d < deltas.length; d++) {
						int nr = sr + deltas[d][0];
						int nc = sc + deltas[d][1];
						if (isIn(nr, nc) && rooms[sr][sc] + 1 == rooms[nr][nc]) {
							moveCnt++;
							canGo = true;
							sr = nr;
							sc = nc;
							break;
						}
					}// 사방 탐색
				}// while
					// 여기까지 떨어진 것은 더이상 탐색할 곳이 없음
				if (moveCnt > maxCnt) {
					maxCnt = moveCnt;
					maxStart = moveStart;
				} else if (moveCnt == maxCnt) {
					maxStart = Math.min(moveStart, maxStart);
				}
			}
		}
		output.append(String.format("#%d %d %d %n", t, maxStart, maxCnt));
	}

	// 30,292 kb, 156 ms
	// 각 출발점 별로 도착점에 대한 정보를 모아놔 보자.
	static void solve2(int t) {
		// 각 출발점 번호를 index로 하는 배열(이동 거리 저장)
		int[] moved = new int[N * N + 1];
		int maxCnt = 0;
		for (int r = 0; r < N; r++) {
			for (int c = 0; c < N; c++) {
				// 어떻든 이미 방문이 완료된 지점은 생략한다.
				if(moved[rooms[r][c]]==-1) {
					//System.out.println("스킵");
					continue;
				}
				int sr = r;
				int sc = c;
				boolean canGo = true;
				int moveCnt = 1;
				int moveStart = rooms[sr][sc];
				outer: while (canGo) {
					canGo = false;
					// 4방 탐색으로 가보기.
					for (int d = 0; d < deltas.length; d++) {
						int nr = sr + deltas[d][0];
						int nc = sc + deltas[d][1];
						if (isIn(nr, nc) && rooms[sr][sc] + 1 == rooms[nr][nc]) {
							// 이미 이동한 흔적이 있다면 거기에 추가해주자. 그리고 더이상 가볼 필요는 없다.
							if (moved[rooms[nr][nc]] != 0) {
								moveCnt += moved[rooms[nr][nc]];
								break outer;
							} else {
								// 중간에 거치는 지점은 사실 이제 관심 없다. 어쨋든 경우지일 경우는 moveStart에서의 이동 거리가 최대이므로 더이상 방문할 필요는 없다.
								moved[rooms[nr][nc]]=-1;
								moveCnt++;
								canGo = true;
								sr = nr;
								sc = nc;
								break;
							}
						}
					}// 사방 탐색
				}// while
				// 업데이트
				moved[moveStart] = moveCnt;
				maxCnt = Math.max(maxCnt, moveCnt);
			}
		}
		for (int i = 0; i < moved.length; i++) {
			if (moved[i] == maxCnt) {
				output.append(String.format("#%d %d %d %n", t, i, maxCnt));
				break;
			}
		}
	}

	//27,760 kb	144 ms
	static void solve3(int t) {
		int[] moved = new int[N * N + 1];
		int maxMoved = 0;
		for (int r = 0; r < N; r++) {
			for (int c = 0; c < N; c++) {
				travelRecur(r, c, moved);
				maxMoved = Math.max(moved[rooms[r][c]], maxMoved);
			}
		}
		for (int i = 0; i < moved.length; i++) {
			if (moved[i] == maxMoved) {
				output.append(String.format("#%d %d %d %n", t, i, maxMoved));
				break;
			}
		}
	}

	// 명확한 의도는? 어떤 좌표에 들어갔을 때 이동 가능 회수를 반환한다.
	static int travelRecur(int r, int c, int[] moved) {
		// base part 1: - 이미 r, c에 대한 이동 경로가 잡혀있는 경우 
		if (moved[rooms[r][c]] > 0) {
			return moved[rooms[r][c]];
		}
		// 할일과 inductive part
		for (int d = 0; d < deltas.length; d++) {
			int nr = r + deltas[d][0];
			int nc = c + deltas[d][1];

			if (isIn(nr, nc) && rooms[nr][nc] == rooms[r][c] + 1) {
				return moved[rooms[r][c]] = 1 + travelRecur(nr, nc, moved);
			}
		}

		// base part 2: - 4방으로 탐색할 수가 없는 경우 
		return 1;
	}

	static boolean isIn(int r, int c) {
		return 0 <= r && r < N && 0 <= c && c < N;
	}

	static String src = "2\r\n" +
						"2\r\n" +
						"1 2\r\n" +
						"3 4\r\n" +
						"3\r\n" +
						"9 3 4\r\n" +
						"6 1 5\r\n" +
						"7 8 2";
}

 

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.