https://www.acmicpc.net/problem/15686
1) 전체 치킨 집들 중에서 중복없이 m개 치킨 집 선택
2) 선택한 m개 치킨 집들에서 치킨 집 1개씩 확인
브루트 포스 + 백트래킹으로 가능한 모든 치킨 가게 조합을 구성하여 확인
List<Coord>
, ArrayList<Coord>
3개: 모든 치킨 집 / 집 좌표들, 선택한 m개 치킨 집 좌표들boolean[]
: 치킨 집 선택(방문) 확인 배열import java.io.*;
import java.util.*;
class Coord {
private int row;
private int col;
public Coord(int row, int col) {
this.row = row;
this.col = col;
}
public int getRow() { return row; }
public int getCol() { return col; }
}
public class Main {
static int n; // n행 n열
static int m; // 선택할 치킨 집 개수
static int minCityDistance = Integer.MAX_VALUE;
// 출력 값: 도시의 최소 치킨 거리 (선택한 m개의 치킨 집과 모든 집들의 거리 합 중 최소)
static List<Coord> homeList = new ArrayList<>(); // 모든 집 좌표들
static List<Coord> chickenList = new ArrayList<>(); // 모든 치킨 가게 좌표들
static List<Coord> selectedChickenList = new ArrayList<>(); // 선택한 m개 치킨 집들
static boolean[] checkChickenList; // chickenList 방문 확인
/* idx: 치킨 집 선택 시작 index */
static void solution(int idx) {
// 치킨 집 m개 선택 완료 => 선택한 m개 치킨 집들과 각 집들의 거리 계산
if (selectedChickenList.size() == m) {
int cityDistance = 0;
for (int i = 0; i < homeList.size(); i++) {
int minDistance = Integer.MAX_VALUE; // 각 집의 최소 치킨 거리
for (Coord chicken : selectedChickenList) {
minDistance = Math.min(
minDistance,
calcDistance(chicken, homeList.get(i))
);
}
cityDistance += minDistance;
}
minCityDistance = Math.min(minCityDistance, cityDistance);
return;
}
// 치킨 집 선택
for (int i = idx; i < chickenList.size(); i++) {
if (!checkChickenList[i]) {
checkChickenList[i] = true;
selectedChickenList.add(chickenList.get(i));
solution(i + 1);
// 재귀 복귀 시점: check 배열 및 선택 리스트 복구
checkChickenList[i] = false;
selectedChickenList.remove(chickenList.get(i));
}
}
}
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());
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++) {
int input = Integer.parseInt(st.nextToken());
if (input == 1)
homeList.add(new Coord(i, j));
else if (input == 2)
chickenList.add(new Coord(i, j));
}
}
checkChickenList = new boolean[chickenList.size()];
// 전체 치킨 집들 중에서, 중복없이 m개 선택
solution(0);
System.out.println(minCityDistance);
}
static int calcDistance(Coord chicken, Coord home) {
int rowDiff = Math.abs(chicken.getRow() - home.getRow());
int colDiff = Math.abs(chicken.getCol() - home.getCol());
return rowDiff + colDiff;
}
}
오답 노트
- 치킨 집 vs 집의 치킨 거리가 최소인 m개 치킨 집을 고른 후,
해당 m개 치킨 집과 각 집의 거리 값을 Math.min() 으로 갱신해서 문제 발생
- 전체 치킨 집에서 m개를 선택하여 가능한 모든 경우의 조합을 찾아서,
해당 조합의 치킨 집들로 각 집의 거리 합 계산해야 함
- 반례 입력
5 2
0 0 0 0 1
0 0 0 0 1
0 0 0 2 1
1 0 2 0 1
2 1 0 0 1
=> 정답 출력: 13
=> 내 오답 출력: 15