좀 어려워 보이는 문제를 잡아봤다. 두 경찰차가 있고, 하나는 1,1에서 나머지 하나는 N,N에서 출발한다. 경찰차가 격자무늬 도시를 돌아다니며 사건들을 해결하는데, 그 과정에서 이동하는 최소값과 경로를 출력하는 문제이다.
처음에 그냥 답이라도 나왔으면 좋겠다 하고 각 사건마다 가장 가까운 경찰차를 이동하면서 문제를 풀었는데, 틀렸다. 당연히 그런게, 만약 두 경찰차가 모두 같은 거리에 떨어져 있으면 이 경우는 어떻게 할지 정의되지 않아 최적해 탐색은 물 건너간다...
머리 쥐어뜯다가 질문 게시판을 탐색해보고 DP 배열 감을 잡았다.
dp[i][j] = 경찰차 1이 가장 마지막으로 i번째 사건을 했고, 경찰차 2가 가장 마지막으로 j번째 사건을 했을 때 이동 최소 거리로 정의를 하자.
이렇게 dp를 구성하면, 각 경찰차의 위치는 사건의 위치를 사용해 구할 수 있다.
우리는 이제 사건을 하나씩 하나씩 보면서 이걸 경찰차 1이 했을 때, 경찰차 2가 했을때로 분기하면서 dp를 채울 수 있다.
그렇다, TSP와 유사하게 DFS를 사용해 사건 수 깊이의 탐색이 이루어진다.
그렇게 탐색을 통해 최소 비용을 구할 수 있다.
그렇다면 경로는 어떻게 해야할까?
여기서 막혀서 더 찾아보니 그냥 거의 비슷하게 탐색하는 방법이 많이 사용되더라. 다만 이때는 두개를 모두 분기할 필요 없이, 이미 DP 배열이 채워 있으므로 각각 값을 찾아서 하나씩 출력이 이루어진다.
#include <iostream>
#include <vector>
#include <cstring>
int g_A_n;
int g_n;
#define MAX 1001
int dp[MAX][MAX];
std::pair<int, int> AList[MAX];
int get_dist(std::pair<int, int> police_car, std::pair<int,int> accident)
{
return (std::abs(police_car.first - accident.first) + std::abs(police_car.second - accident.second));
}
// int dist_dfs(int P1, int P2, std::vector<std::vector<int>> &dp, std::vector<std::pair<int, int> > AList)
int dist_dfs(int P1, int P2)
{
if (P1 == g_A_n || P2 == g_A_n) // 마지막 사건까지 했을 경우
return 0;
if (dp[P1][P2] != -1) return dp[P1][P2]; // dp 배열에 값이 이미 있을 경우
int nextAcc = std::max(P1, P2) + 1; // 다음 사건 번호
int P1Dist, P2Dist;
// 다음 사건을 P1이 할 경우 거리 계산
if (P1 == 0)
P1Dist = get_dist(std::make_pair(1,1), AList[nextAcc]);
else
P1Dist = get_dist(AList[P1], AList[nextAcc]);
// 다음 사건을 P2가 할 경우 거리 계산
if (P2 == 0)
P2Dist = get_dist(std::make_pair(g_n,g_n), AList[nextAcc]);
else
P2Dist = get_dist(AList[P2], AList[nextAcc]);
//각각의 경우 dfs로 탐색
// int P1Result = P1Dist + dist_dfs(nextAcc, P2, dp, AList);
// int P2Result = P2Dist + dist_dfs(P1, nextAcc, dp, AList);
int P1Result = P1Dist + dist_dfs(nextAcc, P2);
int P2Result = P2Dist + dist_dfs(P1, nextAcc);
//두 값 중 낮은 값을 dp에 저장.
dp[P1][P2] = std::min(P1Result, P2Result);
return dp[P1][P2];
}
// void print_route_dfs(int P1, int P2, std::vector<std::vector<int>> dp, std::vector<std::pair<int, int> > AList)
void print_route_dfs(int P1, int P2)
{
if (P1 == g_A_n || P2 == g_A_n) // 마지막 사건까지 했을 경우
return ;
int nextAcc = std::max(P1, P2) + 1; // 다음 사건 번호
int P1Dist, P2Dist;
// 다음 사건을 P1이 할 경우 거리 계산
if (P1 == 0)
P1Dist = get_dist(std::make_pair(1,1), AList[nextAcc]);
else
P1Dist = get_dist(AList[P1], AList[nextAcc]);
// 다음 사건을 P2가 할 경우 거리 계산
if (P2 == 0)
P2Dist = get_dist(std::make_pair(g_n,g_n), AList[nextAcc]);
else
P2Dist = get_dist(AList[P2], AList[nextAcc]);
//각각의 경우 dfs로 탐색
if (dp[nextAcc][P2] + P1Dist < dp[P1][nextAcc] + P2Dist)
{
std::cout << 1 << '\n';
// print_route_dfs(nextAcc, P2, dp, AList);
print_route_dfs(nextAcc, P2);
}
else
{
std::cout << 2 << '\n';
// print_route_dfs(P1, nextAcc, dp, AList);
print_route_dfs(P1, nextAcc);
}
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n;
int A_n;
// std::vector<std::pair<int, int> > AList;
std::cin >> n >> A_n;
g_A_n = A_n;
g_n = n;
// AList.push_back(std::make_pair(-1, -1));
for (int i = 1; i <= A_n; i++)
{
int x, y;
std::cin >> x >> y;
AList[i].first = x;
AList[i].second = y;
// AList.push_back(std::make_pair(x, y));
}
// std::vector<std::vector<int>> dp(g_A_n + 1, std::vector<int>(g_A_n + 1, -1));
memset(dp, -1, sizeof(dp));
// int dist = dist_dfs(0, 0, dp, AList);
int dist = dist_dfs(0, 0);
std::cout << dist << '\n';
// print_route_dfs(0, 0, dp, AList);
print_route_dfs(0, 0);
// std::pair<int, int> P1(0,0);
// std::pair<int, int> P2(n - 1, n - 1);
// std::vector<int> solveList;
// int dist = 0;
// 매 사건마다 가장 가까운 경찰차가 가는걸로 구현해보자. -> 9% 틀렸습니다.
// for (auto accident : AList)
// {
// int P1Dist = get_dist(P1, accident);
// int P2Dist = get_dist(P2, accident);
// if (P1Dist > P2Dist)
// {
// dist += P2Dist;
// solveList.push_back(2);
// P2 = accident;
// }
// else
// {
// dist += P1Dist;
// solveList.push_back(1);
// P1 = accident;
// }
// }
// std::cout << dist << '\n';
// for (int p : solveList)
// std::cout << p << '\n';
}
// 왜 벡터를 주면 타임아웃이 뜨고 전역배열로 하면 잘 되는거지? 무슨 의미인것이지?
주석처리 된것을 보면 알 수 있겠지만, 삽질을 많이 했다. 그리고 왜 안되는건지 더 찾아봐야겠지만, 왜 벡터로 값을 넘겨줬을때는 틀렸습니다가 뜨는지 모르겠다. 벡터로 했을 때 값 샘플 테스트케이스 답 나오는건 확인했는데 왜 계속 틀렸다고... 뜨는지...
전역 배열로 할당해서 접근하니 답이 나온다.. 에휴...
뭔가 DP문제들도 틀이 있는건가?? 싶긴 한데 아직 잘 모르겠다... 더 풀어봐야지!
오늘도 평온한 하루가 되길. 슨민.
'짜잘한 기록' 카테고리의 다른 글
백준 6568 귀도 반 로썸은 크리스마스날 심심하다고 파이썬을 만들었다 (1) | 2021.10.18 |
---|---|
백준 1126 같은 탑 (0) | 2021.10.16 |
백준 2098 외판원 순회 (0) | 2021.10.14 |
프로그래머스 도둑질 (0) | 2021.10.13 |
프로그래머스 등굣길 (0) | 2021.10.13 |