요깨비's LAB

[프로그래머스, JAVA] 땅따먹기 본문

알고리즘(Java)/프로그래머스

[프로그래머스, JAVA] 땅따먹기

요깨비 2019. 12. 16. 18:05
[ 문제 ]

땅따먹기 게임을 하려고 합니다.

땅따먹기 게임의 땅(land)은 총 N행 4열로 이루어져 있고, 모든 칸에는 점수가 쓰여 있습니다.

1행부터 땅을 밟으며 한 행씩 내려올 때, 각 행의 4칸 중 한 칸만 밟으면서 내려와야 합니다.

 단, 땅따먹기 게임에는 한 행씩 내려올 때, 같은 열을 연속해서 밟을 수 없는 특수 규칙이 있습니다.

예를 들면,

| 1 | 2 | 3 | 5 |
| 5 | 6 | 7 | 8 |
| 4 | 3 | 2 | 1 |

로 땅이 주어졌다면, 1행에서 네번째 칸 (5)를 밟았으면, 2행의 네번째 칸 (8)은 밟을 수 없습니다.


마지막 행까지 모두 내려왔을 때, 얻을 수 있는 점수의 최대값을 return하는 solution 함수를 완성해 주세요.

위 예의 경우, 1행의 네번째 칸 (5), 2행의 세번째 칸 (7), 3행의 첫번째 칸 (4) 땅을 밟아

16점이 최고점이 되므로 16을 return 하면 됩니다.


제한사항 

행의 개수 N : 100,000 이하의 자연수

열의 개수는 4개이고, 땅(land)은 2차원 배열로 주어집니다.

점수 : 100 이하의 자연수

입출력 예

land    [[1,2,3,5],[5,6,7,8],[4,3,2,1]]

answer  16

간단한 문제로 생각해서 풀었는데... Test Case는 맞았지만 나머지는 모두 틀려서 0점...
그 이유는 현재 땅 중 방문하지 않았으며 그중에서 가장 큰 땅을 선택하는 Greedy 방식으로 풀어서 전부 틀렸습니다.. (접근 자체가 FAIL)

<Greedy>

// 기존 실패 코드 Greedy 방식
class Solution {
	boolean[] visited = new boolean[4];
	int result = 0;
	int col;

	int solution(int[][] land) {

		col = land.length;

		getMaxInNotVisitedPrevRow(land, 0, -1);

		return result;
	}

	public void getMaxInNotVisitedPrevRow(int[][] land, int colNum, int prevMaxIdx) {
		if (colNum == col)
			return;

		int idx = 0;
		int max = Integer.MIN_VALUE;

		if (colNum == 0) {
			for (int i = 0; i < 4; i++) {
				if (max < land[0][i]) {
					max = land[0][i];
					idx = i;
				}
			}
			visited[idx] = true;
		} else {
			for (int i = 0; i < 4; i++) {
				if (!visited[i] && max < land[colNum][i]) {
					max = land[colNum][i];
					idx = i;
				}
			}
			visited[prevMaxIdx] = false;
			visited[idx] = true;
		}

		result += max;

		getMaxInNotVisitedPrevRow(land, colNum + 1, idx);
	}
}

이후에 DP를 이용해서 매 단계마다 가장 큰 값이 아닌 이전의 방문 경로 중 현재 방문 위치와 겹치지 않으면서 가장 큰 값을 선택하는
방식으로 바꿨습니다.

<DP>

class Solution {
	int[][] dp;
	int[][] map;
	// boolean[] visited = new boolean[4];

	int solution(int[][] land) {
		int answer = 0;

		dp = new int[land.length][land[0].length];
		map = land;

		int col = dp.length;
		int row = dp[0].length;

		for (int i = 0; i < col; i++) {
			for (int j = 0; j < row; j++) {
				dp[i][j] = map[i][j];
			}
		}

		for (int i = 0; i < 4; i++) {
			calculate(1);
		}

//		for (int i = 0; i < col; i++) {
//			for (int j = 0; j < row; j++) {
//				System.out.print(dp[i][j] + " ");
//			}
//			System.out.println();
//		}

		int max = Integer.MIN_VALUE;
		for (int i = 0; i < 4; i++) {
			if (max < dp[col - 1][i])
				max = dp[col - 1][i];
		}

		return max;
	}

	void calculate(int colNum) {
//		int idx = -1;
		if (colNum >= dp.length) {
			return;
		}

		for (int i = 0; i < 4; i++) {
			for(int j=0;j<4;j++) {
				if(i == j)
					continue;
				
				if (dp[colNum][i] < map[colNum][i] + dp[colNum - 1][j]) {
//					idx = i;
					dp[colNum][i] = map[colNum][i] + dp[colNum - 1][j];
				}
			}
			// dp[colNum][i] = Math.max(dp[colNum][i],map[colNum][i] +
			// map[colNum-1][prevIndex]);
		}

		calculate(colNum + 1);
	}
}

 

바로 Greedy를 떠올리다니... 조금 더 숙고하고 생각했으면 혹시라도 DP를 먼저 떠올렸을 수도 있었을 텐데요 심지어
간단한 DP일 뿐인데도 머리 쥐어짜면서 짰습니다.. 열심히 하겠습니다.. 빛이 보이는 날까지

Comments