#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
map<pair<int, int>, int> houseIndex; //row, col에서 집 index 찾아내려고 쓴 map
vector<vector<int>> board;
vector<pair<int, int>> houseVec; //집 위치 저장하는 vector
vector<pair<int, int>> chickenVec; //치킨집 위치 저장하는 vector
vector<vector<int>> dist; //[치킨집 번호][집 번호] 거리
vector<int> minDist; //각 집의 최소 치킨거리
int houseNum; //집 갯수
int chickenNum; //치킨집 갯수
int n, m;
int ans = 10000000000;
//동서남북
int dRow[4] = { 0,0,1,-1 };
int dCol[4] = { 1,-1,0,0 };
//범위 안에 있는지 검사
bool inRange(int row, int col) {
if (1 <= row && row < n + 1 && 1 <= col && col < n + 1)
return true;
return false;
}
//치킨집 번호, 시작 치킨집 row, 시작 치킨집 col
//치킨집을 시작으로 bfs 돌려서 각 집까지의 거리 구하기
void bfs(int cnt, int row, int col) {
queue<pair<int, int>> q;
vector<vector<int>> distance(n + 1, vector<int>(n + 1, -1));
q.push({ row, col });
distance[row][col] = 0;
while (!q.empty()) {
int hereRow = q.front().first;
int hereCol = q.front().second;
int hereDist = distance[hereRow][hereCol];
//집이라면
if (board[hereRow][hereCol] == 1) {
int index = houseIndex[{hereRow, hereCol}]; //row, col에서 집 index 알아내기
dist[cnt][index] = hereDist; //dist에 저장
}
q.pop();
for (int i = 0; i < 4; i++) {
int thereRow = hereRow + dRow[i];
int thereCol = hereCol + dCol[i];
if (inRange(thereRow, thereCol) && distance[thereRow][thereCol] == -1) {
q.push({ thereRow, thereCol });
distance[thereRow][thereCol] = hereDist + 1;
}
}
}
}
//cnt번재 고를거야
void recursive(int cnt, int index, vector<int>& select) {
if (cnt == m + 1) {
//select에 m개
//모든 집에대해 최소 치킨 거리 구하기
for (int j = 0; j < houseNum; j++) {
int tempMin = 1000000;
for (int k = 0; k < select.size(); k++) {
int i = select[k]; //select에서 고른 치킨집만
tempMin = min(dist[i][j], tempMin);
}
minDist[j] = tempMin;
}
int tempAns = 0;
for (int i = 0; i < minDist.size(); i++) {
tempAns += minDist[i]; //각 집의 치킨 거리 더하기
}
ans = min(ans, tempAns);
return;
}
for (int i = index; i < chickenNum; i++) {
select.push_back(i);
recursive(cnt + 1, i + 1, select);
select.pop_back();
}
}
int main() {
scanf("%d %d", &n, &m);
board = vector<vector<int>>(n + 1, vector<int>(n + 1));
int houseCnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &board[i][j]);
if (board[i][j] == 1) {
houseVec.push_back({ i,j });
houseIndex[{i, j}] = houseCnt;
houseCnt++;
}
else if (board[i][j] == 2)
chickenVec.push_back({ i,j });
}
}
houseNum = houseVec.size();
chickenNum = chickenVec.size();
dist = vector<vector<int>>(chickenNum, vector<int>(houseNum));
minDist = vector<int>(houseNum);
//////////////////////////////////
//치킨집 기준 bfs
for (int i = 0; i < chickenNum; i++) {
bfs(i, chickenVec[i].first, chickenVec[i].second);
}
vector<int> select;
recursive(1,0, select);
printf("%d", ans);
return 0;
}
앞으로는 푸는데 걸린 시간도 써야지
소요 시간: 50분
치킨 집에서 bfs를 시작할지 집에서 bfs를 시작할지 고민하다가 치킨집은 최대 13개뿐이니까 치킨집에서 bfs를 시작하기로 결정
다른 분들 보니까 dfs 쓰신분도 많던데 난 아직 저 문제를 보고 dfs를 써야겠다는 생각이 안들었다.. 아직 부족하다 많이ㅜ
거리라고해서 무조건 bfs를 돌렸는데 생각해보니 각각 가중치가 있는것도 아니고 거리 공식이 있는데 왜 bfs를 돌렸을까
그냥 치킨집 m개 재귀돌리면서 뽑고 각 집에서 뽑아진 치킨집에 대해 거리 구하면 될걸 너무 어렵게 풀었다 (밑에 코드).... bfs 한번 더 연습한셈 치자
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <math.h>
using namespace std;
vector<vector<int>> board;
vector<pair<int, int>> houseVec; //집 위치 저장하는 vector
vector<pair<int, int>> chickenVec; //치킨집 위치 저장하는 vector
int houseNum; //집 갯수
int chickenNum; //치킨집 갯수
int n, m;
int ans = 10000000000;
//동서남북
int dRow[4] = { 0,0,1,-1 };
int dCol[4] = { 1,-1,0,0 };
//범위 안에 있는지 검사
bool inRange(int row, int col) {
if (1 <= row && row < n + 1 && 1 <= col && col < n + 1)
return true;
return false;
}
//cnt번재 고를거야
void recursive(int cnt, int index, vector<int>& select) {
if (cnt == m + 1) {
//select에 m개
vector<int> minDist(houseNum, 100000000);
//모든 집에대해 최소 치킨 거리 구하기
for (int j = 0; j < houseNum; j++) {
for (int k = 0; k < select.size(); k++) {
int i = select[k]; //select에서 고른 치킨집만
minDist[j] = min(minDist[j], abs(houseVec[j].first - chickenVec[i].first) + abs(houseVec[j].second - chickenVec[i].second));
}
}
int tempAns = 0;
for (int i = 0; i < minDist.size(); i++) {
tempAns += minDist[i]; //각 집의 치킨 거리 더하기
}
ans = min(ans, tempAns);
return;
}
for (int i = index; i < chickenNum; i++) {
select.push_back(i);
recursive(cnt + 1, i + 1, select);
select.pop_back();
}
}
int main() {
scanf("%d %d", &n, &m);
board = vector<vector<int>>(n + 1, vector<int>(n + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &board[i][j]);
if (board[i][j] == 1)
houseVec.push_back({ i,j });
else if (board[i][j] == 2)
chickenVec.push_back({ i,j });
}
}
houseNum = houseVec.size();
chickenNum = chickenVec.size();
//////////////////////////////////
vector<int> select;
recursive(1, 0, select);
printf("%d", ans);
return 0;
}
https://www.acmicpc.net/problem/15686
15686번: 치킨 배달
크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸
www.acmicpc.net
'Baekjoon' 카테고리의 다른 글
[#15684] 사다리 조작 (0) | 2020.10.15 |
---|---|
[#14503] 로봇 청소기 (0) | 2020.10.13 |
[#16236] 아기상어 (0) | 2020.10.12 |
[#14502] 연구소 (0) | 2020.10.12 |
[#14499] 주사위 굴리기 (0) | 2020.10.11 |