문제에서 도시의 치킨 거리를 최소화하는 것이 목표
|r1 - r2| + |c1 - c2| (맨해튼 거리)이다.제약 조건
정답
👉 도시의 치킨 거리의 최솟값을 출력.
입력 받기
조합 생성
도시 치킨 거리 계산
최솟값 갱신
변수
house: 집 좌표 리스트chicken: 치킨집 좌표 리스트selected: 현재 선택된 치킨집 조합result: 도시 치킨 거리 최솟값흐름
house, chicken 리스트 채우기pickChickenComb() 호출 (조합으로 뽑기)calcChickenDist() 실행calcChickenDist()를 통해 도시 치킨 거리 계산result로 갱신사용 알고리즘
해당 알고리즘을 선택한 근거
C(13, 6) = 1716 → 충분히 가능.
package Baekjoon;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class B_15686_치킨배달 {
static int N, M, pickChickenCount, n, r, cityChickenDist, result;
static int[][] arr;
static List<int[]> house;
static List<int[]> chicken;
static List<int[]> selected;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
arr = new int[N][N];
pickChickenCount = M;
house = new ArrayList<>();
chicken = new ArrayList<>();
selected = new ArrayList<>();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
arr[i][j] = sc.nextInt();
// 좌표 저장 [ 0 빈칸 / 1 집 / 2 치킨집 ]
if (arr[i][j] == 1) {
house.add(new int[]{i,j});
} else if (arr[i][j] == 2) {
chicken.add(new int[]{i,j});
}
}
}
//로직
//임의의 두 칸 (r1, c1)과 (r2, c2) 사이의 거리는 |r1-r2| + |c1-c2|로 구한다.
//치킨 거리는 집과 가장 가까운 치킨집 사이의 거리
//즉, 치킨 거리는 집을 기준으로 정해지며, 각각의 집은 치킨 거리를 가지고 있다.
//도시의 치킨 거리는 모든 집의 치킨 거리의 합이다.
//살릴 치킨 집 개수가 지금 지도 상에 있는 치킨 집 개수보다 많을 때
//일단 어떤 치킨 집을 살릴지 골라야돼서
//조합으로 치킨 집 뽑아서 저장 하려고
//치킨 집 뽑는 함수 => pickChickenComb()
if (chicken.size() > M) {
int n = chicken.size();
int r = M;
result = Integer.MAX_VALUE;
pickChickenComb(0, 0);
} else {
result = calcChickenDist(chicken);
}
//출력
System.out.println(result);
}
// 조합 뽑기
static void pickChickenComb(int start, int depth) {
if (depth == M) {
// M개 선택 완료 → 도시 치킨 거리 계산
result = Math.min(calcChickenDist(selected), result);
return;
}
for (int i = start; i < chicken.size(); i++) {
selected.add(chicken.get(i)); // i번째 치킨집 선택
pickChickenComb(i + 1, depth + 1); // 다음 조합 뽑기
selected.remove(selected.size() - 1); // 백트래킹
}
}
//도시의 치킨 거리는 모든 집의 치킨 거리의 합이다.
static int calcChickenDist(List<int[]> targetChickenList) {
cityChickenDist = 0;
for (int[] target : house) {
int chickenDist = Integer.MAX_VALUE;
for (int[] chicken : targetChickenList) {
int r1 = target[0];
int c1 = target[1];
int r2 = chicken[0];
int c2 = chicken[1];
chickenDist = Math.min(chickenDist, Math.abs(r1 - r2) + Math.abs(c1 - c2)); // 한 집의 치킨 거리
}
cityChickenDist += chickenDist;
}
return cityChickenDist;
}
}
static void pickChickenComb(int start, int depth) {
if (depth == M) {
result = Math.min(calcChickenDist(selected), result);
return;
}
for (int i = start; i < chicken.size(); i++) {
selected.add(chicken.get(i));
pickChickenComb(i + 1, depth + 1);
selected.remove(selected.size() - 1); // 백트래킹
}
}
치킨집 리스트(chicken)에서 M개를 선택하는 모든 조합을 생성하고,
각 조합에 대해 calcChickenDist(selected) 를 호출해 도시 치킨 거리 합을 구한 뒤 result(최솟값)를 갱신
start : 다음 선택 가능한 치킨집의 시작 인덱스. 중복 조합을 막고 오름차순으로 선택하도록 보장한다.
depth : 현재까지 선택한 치킨집의 개수 (selected.size()와 동일한 값).
if (depth == M)for (int i = start; i < chicken.size(); i++)static int calcChickenDist(List<int[]> targetChickenList) {
int cityChickenDist = 0;
for (int[] target : house) {
int chickenDist = Integer.MAX_VALUE;
for (int[] chicken : targetChickenList) {
int r1 = target[0], c1 = target[1];
int r2 = chicken[0], c2 = chicken[1];
chickenDist = Math.min(chickenDist, Math.abs(r1 - r2) + Math.abs(c1 - c2));
}
cityChickenDist += chickenDist;
}
return cityChickenDist;
}
주어진 targetChickenList (선택된 치킨집들)에 대해 각 집이 갖는 최소 치킨 거리를 모두 더해 도시의 치킨 거리를 반환
cityChickenDist : 모든 집들의 치킨 거리 합 (최종 반환값)target : house 리스트에서 현재 처리 중인 집의 좌표 (int[] {r, c})chickenDist : 해당 집이 갖는 가장 가까운 치킨집과의 거리. 초기값을 Integer.MAX_VALUE 로 둬서 비교로 최소값을 갱신chicken : targetChickenList의 각 치킨집 좌표chickenDist = Integer.MAX_VALUE 로 초기화Math.abs(r1 - r2) + Math.abs(c1 - c2) (맨해튼 거리)chickenDist = Math.min(chickenDist, computedDistance) 로 최소값 유지chickenDist 를 cityChickenDist에 누적cityChickenDist 반환
비밀 댓글입니다