포스트

[백준][15686] 치킨 배달

이 포스트는 백준 사이트의 치킨 배달 문제 풀이입니다.

문제

문제


첫 번째 시도(실패)

여러 개의 치킨 가게 중 M 개만 선택하였을 때, 도시의 치킨 거리가 최소인 경우를 구해야 합니다.
여기서 M 개의 가게 선택을 위해 조합을 사용하고
조합으로 선택된 가게들에서 집들까지의 최소 거리를 반복해서 갱신해 정답을 구하고자 하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

#define IO_SETTING std::ios::sync_with_stdio(false)
#define INPUT_SETTING std::cin.tie(0)

int N, M;
vector<vector<int>> board;
vector<vector<int>> store;
vector<vector<int>> store_combination;
vector<vector<int>> distance_log;

void input() {
	cin >> N >> M;
	board.assign(N, vector<int>(N, 0));

	for (int row = 0; row < N; ++row) {
		for (int col = 0; col < N; ++col) {
			cin >> board[row][col];

			if (board[row][col] == 2) {
				store.emplace_back(vector<int>{row, col});
			}
		}
	}
}

void make_store_combination() {
	vector<bool> select(N, false);
	for (int number = 0; number < M; ++number) {
		select[number] = true;
	}

	do {
		vector<int> curr_store_combination;
		for (int number = 0; number < N; ++number) {
			if (select[number]) {
				curr_store_combination.push_back(number);
			}
		}
		store_combination.push_back(curr_store_combination);
	} while (prev_permutation(select.begin(), select.end()));
}

void refresh_chicken_distance(int start_row, int start_col) {
	// clockwise direction (00 ~ 12)
	int dir_row[8]{ -1, -1, 0, 1, 1, 1, 0, -1 };
	int dir_col[8]{ 0, 1, 1, 1, 0, -1, -1, -1 };

	queue<vector<int>> q;
	q.push({ start_row, start_col, 0 });
	vector<vector<bool>> visited(N, vector <bool>(N, false));
	visited[start_row][start_col] = true;

	while (false == q.empty()) {
		vector<int> point = q.front();
		q.pop();

		for (int dir = 0; dir < 8; ++dir)
		{
			int new_row = point[0] + dir_row[dir];
			int new_col = point[1] + dir_col[dir];

			if (new_row < 0 || new_row >= N || new_col < 0 || new_col >= N)
				continue;
			if (visited[new_row][new_col])
				continue;

			visited[new_row][new_col] = true;
			int curr_distance = (abs(new_row - start_row) + abs(new_col - start_col));

			if (1 == board[new_row][new_col]) {
				distance_log[new_row][new_col] 
					= min(curr_distance, distance_log[new_row][new_col]);
			}
			else {
				q.push({ new_row, new_col, point[2] + 1 });
			}
		}
	}
}

int get_city_chicken_distance() {
	
	int min_distance = 2e9;

	for (auto points : store_combination) {
		distance_log.assign(N, vector<int>(N, 2e9));
		for (int store_number : points) {
			refresh_chicken_distance(store[store_number][0], store[store_number][1]);
		}

		int curr_distance = 0;
		for (int row = 0; row < N; ++row) {
			for (int col = 0; col < N; ++col) {
				if (board[row][col] == 1) {
					curr_distance += distance_log[row][col];
				}
			}
		}
		min_distance = min(min_distance, curr_distance);

		if (store.size() == M) {
			break;
		}
	}
	return min_distance;
}

int main() {
	input();
	make_store_combination();
	cout << get_city_chicken_distance();
	return 0;
}

그러나 위의 코드는 메모리 초과로 인해서 오답이 되었습니다.
그래서 사용하지 않는 데이터를 없애기 위해
지도 전체를 저장하는 board 를 제거하고
대신 모든 집과 치킨 가게의 위치만 저장 하는 houses, store 벡터를 만들었습니다.

그리고 이전처럼 치킨 가게들의 조합을 구한 뒤
선택된 가게에서 각 집까지의 거리를 구해 최소의 도시의 치킨 거리를 구했습니다.

두 번째 시도(정답)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

#define IO_SETTING std::ios::sync_with_stdio(false)
#define INPUT_SETTING std::cin.tie(0)

int N, M;
vector<vector<int>> houses;
vector<vector<int>> store;
vector<vector<int>> store_combination;

void input() {
	cin >> N >> M;
	for (int row = 0; row < N; ++row) {
		for (int col = 0, temp; col < N; ++col) {
			cin >> temp;
			if (temp == 1) {
				houses.emplace_back(vector<int>{row, col});
			} else if (temp == 2) {
				store.emplace_back(vector<int>{row, col});
			}
		}
	}
}

void make_store_combination() {
	vector<bool> select((int)store.size(), false);
	for (int number = 0; number < M; ++number) {
		select[number] = true;
	}

	do {
		vector<int> curr_store_combination;
		for (int number = 0; number < (int)store.size(); ++number) {
			if (select[number]) {
				curr_store_combination.push_back(number);
			}
		}
		store_combination.push_back(curr_store_combination);
	} while (prev_permutation(select.begin(), select.end()));
}

int get_city_chicken_distance() {
	int city_chicken_distance = 2e9;
	for (auto alive_store : store_combination) {

		int alive_store_distance = 0;
		for (auto house_position : houses) {
			int curr_distance = 2e9;
			for (int number : alive_store) {
				int distance = abs(house_position[0] - store[number][0]) + abs(house_position[1] - store[number][1]);
				curr_distance = min(curr_distance, distance);
			}
			alive_store_distance += curr_distance;
		}
		city_chicken_distance = min(city_chicken_distance, alive_store_distance);
	}
	return city_chicken_distance;
}

int main() {
	input();
	make_store_combination();
	cout << get_city_chicken_distance();
	return 0;
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.