전체 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class 백준_15686_치킨배달 {
static int N, M, MIN = Integer.MAX_VALUE, size;
static class Point { // 좌표 저장용 클래스
int y;
int x;
Point(int y, int x) {
this.y = y;
this.x = x;
}
}
static ArrayList<Point> chks; // 치킨집들
static ArrayList<Point> homes; // 가정집들
static int[] nums, sel; // 조합에 쓰일 배열들
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());
int tmp;
chks = new ArrayList<Point>(); //치킨집과 가정집을 ArrayList로 준비한다.
homes = new ArrayList<Point>();
for (int i = 0; i < N; i++) { // 위치들은 Point클래스에 담기므로 따로 배열에 저장하지 않는다.
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
tmp = Integer.parseInt(st.nextToken());
if (tmp == 2) { //값이 2면 치킨집에 좌표를 저장하고, 1이면 가정집에 저장한다.
chks.add(new Point(j, i));
} else if (tmp == 1) {
homes.add(new Point(j, i));
}
}
}
size = chks.size(); // 밑에서 자주쓰일 치킨집 사이즈
nums = new int[size];
sel = new int[M];
for (int i = 0; i < size; i++) {
nums[i] = i; // 치킨집 사이즈 만큼 0~size-1까지 초기화 해준다 (인덱스 역할)
}
combination(0, 0); // 조합 시작
System.out.println(MIN);
}
public static void combination(int idx, int k) {
if (k == M) { // 배열 중 중복되지 않는 M개의 치킨집을 고른다.
int sum = 0;
for (Point home : homes) {
sum += getMin(sel, home); // 고른 치킨집들과 가정집들 간의 전체 최소거리를 구하고
}
if (MIN > sum) { // 모든 조합들 중 최소값을 구한다.
MIN = sum;
}
return;
}
if (idx == size)
return;
sel[k] = nums[idx];
combination(idx + 1, k+1);
combination(idx + 1, k);
}
public static int getMin(int[] idxs, Point home) {
int min = Integer.MAX_VALUE, tmp;
for (int idx : idxs) { // 조합에서 들어온 인덱스의 치킨집들 중 집 하나와의 거리가 가장 가까운 것을 리턴한다.
Point chk = chks.get(idx);
tmp = Math.abs(home.y - chk.y) + Math.abs(home.x - chk.x);
if (min > tmp) {
min = tmp;
}
}
return min;
}
}
문제 핵심 코드
public static void combination(int idx, int k) {
if (k == M) { // 배열 중 중복되지 않는 M개의 치킨집을 고른다.
int sum = 0;
for (Point home : homes) {
sum += getMin(sel, home); // 고른 치킨집들과 가정집들 간의 전체 최소거리를 구하고
}
if (MIN > sum) { // 모든 조합들 중 최소값을 구한다.
MIN = sum;
}
return;
}
if (idx == size)
return;
sel[k] = nums[idx];
combination(idx + 1, k+1);
combination(idx + 1, k);
}
public static int getMin(int[] idxs, Point home) {
int min = Integer.MAX_VALUE, tmp;
for (int idx : idxs) { // 조합에서 들어온 인덱스의 치킨집들 중 집 하나와의 거리가 가장 가까운 것을 리턴한다.
Point chk = chks.get(idx);
tmp = Math.abs(home.y - chk.y) + Math.abs(home.x - chk.x);
if (min > tmp) {
min = tmp;
}
}
return min;
}
조합을 적절히 이용하면 아주 쉬운 문제였다! 치킨집들의 조합과 최소 거리를 구하는 부분을 잘 캐치했으면 충분히 가능했을 것이다.
'알고리즘문제풀이' 카테고리의 다른 글
[JAVA] 백준 3109 빵집 [ 백트래킹 ] (0) | 2020.08.27 |
---|---|
[JAVA] 백준 2206 벽 부수고 이동하기 [BFS] (0) | 2020.08.26 |
[JAVA] SWEA 1859 백만 장자 프로젝트 (0) | 2020.08.25 |
[JAVA] 백준 1463 1로 만들기 [ Dynamic Programming ] (0) | 2020.08.23 |
[JAVA] SWEA 4615 재미있는 오셀로게임 (0) | 2020.08.21 |