티스토리 뷰

공부/PS

[BOJ] 15686: 치킨 배달

복소평면 2020. 7. 5. 15:55

https://www.acmicpc.net/problem/15686

 

15686번: 치킨 배달

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸

www.acmicpc.net

간단한 문제다.

 

순열을 생성해서 풀 수도 있고, 재귀함수로 가능한 경우를 모두 탐색해도 풀 수 있고, 비트마스킹을 써서 풀 수도 있다.

 

재귀함수로 가능한 경우를 모두 탐색하는 경우는

치킨 집이 N개 존재한다면, N개의 치킨집에 대해 각각 고른다/고르지 않는다를 선택할 수 있으니 O(2^N)이다.

 

순열이나 비트마스킹으로 푸는 경우 또한 치킨집의 개수가 N개일 때, (1<<N)번 반복하기 때문에 O(2^N)이다.

치킨집은 최대 13개이니, 2^13 = 8192로 넉넉하게 풀 수 있다.

 

int minDist = 10e8;
for (int i = 1; i < (1 << numOfChickens); ++i) {
  int cnt = __builtin_popcount(i);
  if (cnt > M) continue;
  minDist = std::min(minDist, getAllDistances(i));
}

 

비트마스킹으로 풀 경우 달라지는 부분이다.

 

int solve(int index, int count = 0) {
	if (index == numOfChickens) {
		return (count <= M) ? getAllDistances() : 10e8;
	}

	int ret = solve(index + 1, count);

	if (count < M) {
		std::get<2>(chickens[index]) = true;
		ret = std::min(ret, solve(index + 1, count + 1));
		std::get<2>(chickens[index]) = false;
	}
	return ret;
}

 

재귀함수로 풀 경우 달라지는 부분이다.

 

 

 

비트마스킹 전체 코드

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>

int N, M;
int a[50][50];
std::vector<std::pair<int, int>> chickens;
std::vector<std::pair<int, int>> houses;
int numOfChickens;

int getDistance(int r1, int c1, int r2, int c2) {
	return abs(r1 - r2) + abs(c1 - c2);
}

int getAllDistances(int state) {
	int distance = 0;
	for (const auto& house : houses) {
		int minDistance = 0;
		for (int i = 0; i < numOfChickens; ++i) {
			if ((state & (1 << i)) == 0) continue;
			int r2 = chickens[i].first, c2 = chickens[i].second;
			int dist = getDistance(house.first, house.second, r2, c2);
			if (minDistance == 0)
				minDistance = dist;
			else
				minDistance = std::min(minDistance, dist);
		}
		distance += minDistance;
	}
	if (distance == 0) {
		distance = 10e8;
	}
	return distance;
}

int main() {
  std::cin >> N >> M;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      std::cin >> a[i][j];
      if (a[i][j] == 1) {
        houses.push_back({ i, j });
      }
      if (a[i][j] == 2) {
        chickens.push_back({ i, j });
      }
    }
  }

  numOfChickens = chickens.size();

  int minDist = 10e8;
  for (int i = 1; i < (1 << numOfChickens); ++i) {
    int cnt = __builtin_popcount(i);
    if (cnt > M) continue;
    minDist = std::min(minDist, getAllDistances(i));
  }

  std::cout << minDist;

  return 0;
}

 

재귀함수 전체 코드

#include <iostream>
#include <vector>
#include <tuple>
#include <cmath>
#include <algorithm>

int N, M;
int a[50][50];
std::vector<std::tuple<int, int, bool>> chickens;
std::vector<std::pair<int, int>> houses;
int numOfChickens;

int getDistance(int r1, int c1, int r2, int c2) {
	return abs(r1 - r2) + abs(c1 - c2);
}

int getAllDistances() {
	int distance = 0;
	for (const auto& house : houses) {
		int minDistance = 0;
		for (const auto& chicken : chickens) {
			int r2, c2; bool active;
			std::tie(r2, c2, active) = chicken;
			if (!active) continue;

			int dist = getDistance(house.first, house.second, r2, c2);
			if (minDistance == 0)
				minDistance = dist;
			else
				minDistance = std::min(minDistance, dist);
		}
		distance += minDistance;
	}
	if (distance == 0) {
		distance = 10e8;
	}
	return distance;
}

int solve(int index, int count = 0) {
	if (index == numOfChickens) {
		return (count <= M) ? getAllDistances() : 10e8;
	}

	int ret = solve(index + 1, count);

	if (count < M) {
		std::get<2>(chickens[index]) = true;
		ret = std::min(ret, solve(index + 1, count + 1));
		std::get<2>(chickens[index]) = false;
	}
	return ret;
}

int main() {
	std::cin >> N >> M;
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			std::cin >> a[i][j];
			if (a[i][j] == 1) {
				houses.push_back({ i, j });
			}
			if (a[i][j] == 2) {
				chickens.push_back({ i, j, false });
			}
		}
	}
	numOfChickens = chickens.size();
	std::cout << solve(0);

	return 0;
}

'공부 > PS' 카테고리의 다른 글

[BOJ] 16988: Baaaaaaaaaduk2 (Easy)  (0) 2020.07.09
[BOJ] 17406: 배열 돌리기 4  (0) 2020.07.06
[BOJ] 17088: 등차수열 변환  (0) 2020.07.05
[BOJ] 15683: 감시  (0) 2020.07.04
[BOJ] 16637: 괄호 추가하기  (0) 2020.07.04
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/11   »
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
글 보관함