알고리즘/문제풀이
[백준] Q15686 치킨 배달 JAVA
케팔스
2022. 1. 18. 22:22
https://www.acmicpc.net/problem/15686
15686번: 치킨 배달
크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸
www.acmicpc.net
1. 문제의 이해 및 유형
완전탐색 (조합), 구현
"치킨 거리" 집과 가장 가까운 치킨 집 사이의 거리.
구하고자 하는 것이 "도시의 치킨 거리" : 도시에 위치한 집들의 치킨거리 합
도시의 치킨거리가 가장 작도록 골랐을 때 치킨거리의 최소값 구하기.
치킨 집 개수인 M이 $1<= N <= 13$개로, 가장 많은 집인 13개에서 가장 큰 값을 구한다면
13C6일 때이고 이 때 1716 가지 경우의 수 밖에 없기 떄문에 완전탐색이라고 생각했다.
2. 문제 접근 방식
위와 동일하다.
다만, 자료 정리에 있어서 치킨 거리 계산에는 치킨집의 좌표와 도시에 있는 집의 좌표만 있으면 되기 때문에
list를 통해 자료를 잘 정리해두고 필요에 따라 값만 계산하면된다.
/*
2021.12.19
문제번호 : Q15686
이름 및 난이도 : 치킨 배달 Gold V
문제이해
-----------------
N*N 도시. 빈칸, 치킨집, 집
r,c 는 1부터 시작
"치킨거리" >> 집과 가장 가까운 치킨집 사이의 거리.
"도시의 치킨거리" >> 모든 집의 치킨 거리 합
|r1-r2| + |c1-c2|
0 빈칸 1 집 2 치킨집
최대 M개 (수익을 많이 낼 수 있는)
치킨 거리가 가장 작게 .
접근 방법 :
모든 집으로부터 치킨 집까지의 거리를 다 더하는 치킨거리가 총합이 된다.
한 집에서 가장 가깝다고 해서 다른 집도 가까운 상황이 아님.
할 수 있는 방법은 여러가지가 있을 것 같다.
1. 치킨집 마다 치킨거리를 다 구해서 sorting시킨다음.
가장 긴 치킨거리를 가지는 치킨 집 부터 제거하여 M개를 만드는 방법.(X)
잘못된 생각임.
2. 치킨집 개수가 최대 13개 이고 13에서 가장 큰 조합의 개수는
13C6 = 1716
조합 마다 하는 방법
>조합마다 해보는 방법은 같은 치킨집에서의 거리를 구한다.
제한 조건 :
N 50 M 13 치킨집 개수 <= Min(M,13)
## 중복 허용 X 오름차순
## 참조 https://www.acmicpc.net/source/32167915
*/
import java.io.*;
import java.util.*;
public class Main {
static int N;
static int M;
static ArrayList<Point> house;
static ArrayList<Point> chicken;
static boolean[] possible;
static int ans;
public static void main(String[] args) throws IOException {
input();
solution();
}
public static void input() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
house = new ArrayList<Point>();
chicken = new ArrayList<Point>();
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 option = Integer.parseInt(st.nextToken());
if (option == 1) {
house.add(new Point(i, j));
} else if (option == 2) {
chicken.add(new Point(i, j));
}
}
}
possible = new boolean[chicken.size()];
}
public static void solution() {
ans = Integer.MAX_VALUE;
// M개를 골랐을 때
selectChickenHouse(0, 0);
System.out.println(ans);
}
//조합
public static void selectChickenHouse(int depth, int idx) {
if (depth == M) {
int cityDist = 0;
for (Point h : house) {
int chickenDist = Integer.MAX_VALUE;
for (int i = 0; i < chicken.size(); i++) {
if (!possible[i])
continue;
Point c = chicken.get(i);
chickenDist = Math.min(chickenDist, Math.abs(h.x - c.x) + Math.abs(h.y - c.y));
}
cityDist += chickenDist;
}
ans = Math.min(ans, cityDist);
return;
}
if (chicken.size() - idx < M - depth)
return;
for (int i = idx; i < chicken.size(); i++) {
if (!possible[i]) {
possible[i] = true;
selectChickenHouse(depth + 1, i + 1);
possible[i] = false;
}
}
}
static class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
}
3. 문제점
이 문제를 작성하고 싶었던 건 사실 개인적으로 '백준 - 연구소https://www.acmicpc.net/problem/14502' 를 처음 풀 때 너무 감명받아서 비슷한 느낌의 문제를 보고 다시 한번 생각해보지 않고 작성했었기 때문에 조심하기 위해서...