Algorithm/Problem Solving
[SWEA/모의 SW역량테스트] 2115. 벌꿀 채취 - JAVA 자바
gangintheremark
2024. 2. 29. 15:31
728x90
- 123ms
구현
부분집합
DFS
이 문제는 가로로 연속된 M개의 칸에서 채취할 수 있는 꿀의 최대 양(C)을 넘지 않으면서 최대한 많은 꿀의 양을 채취할 수 있는 두 구간을 찾아내는 문제이다.
이 문제의 핵심은
- 두 구간이 겹치면 안된다 → 즉, M개의 칸 중 일부칸만 이용했더라도 M개의 칸 전체와 겹치면 안됨
- 연속된 M개의 칸을 선택한 후 채취할 꿀 칸을 선택하는 건 연속하지 않아도 된다 (아래그림 참조)
행마다 최대수익을 얻는 경우를 찾은 후, 그 중 최대수익이 가장 큰 행을 찾아 그 값을 결과에 더하고 다시 그 행만 최대수익을 구해준다. (단, 이전에 선택된 칸은 제외) 다시 행마다 최대수익이 가장 큰 행을 찾아 결과에 더해주며 해결하였다.
- 조건에 맞게 구할 수 있는 조합에서 최대 수익을 얻는 경우 찾기 ⇒
selected
함수- M개의 칸 중 해당 칸을 포함한다/포함하지 않는다 ⇒ 부분집합, DFS
- 행마다 1번을 반복하여 최대수익과 채취한 벌통의 좌표리스트
rowValue[행]
에 저장
- 최대 수익 중 가장 큰 수익을 가진 행 선택 후 최대수익은 결과값에 더한 후, 최대수익 값 초기화 및 채취한 별통의 열 좌표는 방문체크
- 2번에서 선택된 행만 다시 최대수익을 얻는 경우 찾기
selected
(단, 방문체크된 좌표는 X) - 다시 최대 수익 중 가장 큰 수익을 가진 행 선택 후 최대 수익은 결과값에 더하기
# 소스코드
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/*
* 가로로 m개의 벌통을 선택할 수 있고, 채취할 수 있는 꿀의 최대는 c
*/
public class Solution {
static int result, n, m, c;
static int[][] board;
static boolean[][] visited;
static Node[] rowValue;
static List<int[]> honeyList = new ArrayList<>();
static List<Point> combi = new ArrayList<>();
static class Node {
int money; // 최대수익
List<int[]> points = new ArrayList<>(); // 채취한 벌통의 좌표 리스트 (1~m개)
public Node(int money, List<int[]> points) {
this.money = money;
this.points = points;
}
}
static class Point {
int x;
int y;
int value;
public Point(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
}
public static void selected(int index, int cnt, int amount, int row) {
if (index > m || amount > c)
return;
if (index == m) {
int sum = 0;
for (Point p : combi)
sum += p.value * p.value;
if (rowValue[row].money < sum) {
rowValue[row].money = sum;
rowValue[row].points.clear();
for (Point p : combi)
rowValue[row].points.add(new int[] { p.x, p.y });
}
return;
}
Point p = new Point(honeyList.get(index)[0], honeyList.get(index)[1],
board[honeyList.get(index)[0]][honeyList.get(index)[1]]);
combi.add(p);
selected(index + 1, cnt + 1, amount + p.value, row);
combi.remove(p);
selected(index + 1, cnt, amount, row);
}
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for (int t = 1; t <= T; t++) {
st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken()); // m개 중 채취할 벌통 선택
c = Integer.parseInt(st.nextToken());
board = new int[n][n];
rowValue = new Node[n];
visited = new boolean[n][n];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++)
board[i][j] = Integer.parseInt(st.nextToken());
}
for (int i = 0; i < n; i++) {
// i 행 마다 최대 수익 구하기
rowValue[i] = new Node(0, new ArrayList<>());
for (int j = 0; j <= n - m; j++) {
// j부터 j+m 까지 추출 후 부부집합찾기
for (int k = j; k < j + m; k++)
honeyList.add(new int[] { i, k });
// 추출한 honeyList 에서 최대 수익과 그 좌표 구하기
selected(0, 0, 0, i);
honeyList.clear();
}
}
// 행마다 구한 최대 수익 중 가장 수익이 큰 행 구하기
int index = 0, max = 0;
for (int i = 0; i < rowValue.length; i++) {
if (max < rowValue[i].money) {
max = rowValue[i].money;
index = i;
}
}
result += rowValue[index].money;
// 방문체크
rowValue[index].money = 0;
for (int i = 0; i < rowValue[index].points.size(); i++)
visited[index][rowValue[index].points.get(i)[1]] = true;
// 인덱스 행의 최대 수익 다시 구하기
for (int j = 0; j <= n - m; j++) {
// j부터 j+m 까지 추출 후 부부집합찾기 단, 방문체크가 안된 구역만
for (int k = j; k < j + m; k++) {
if (visited[index][k])
break;
honeyList.add(new int[] { index, k });
}
// 추출한 honeyList 에서 최대 수익과 그 좌표 구하기
if (honeyList.size() == m)
selected(0, 0, 0, index);
honeyList.clear();
}
max = 0;
index = 0;
for (int i = 0; i < rowValue.length; i++) {
if (max < rowValue[i].money) {
max = rowValue[i].money;
index = i;
}
}
result += rowValue[index].money;
sb.append('#').append(t).append(' ').append(result).append('\n');
result = 0;
}
System.out.println(sb);
}
}
코드에 대한 피드백은 언제나 환영입니다🧚🏻♀️
728x90