왼쪽 부터 오른쪽으로 순회한 뒤 순회하지 않은 정점들을 오른쪽에서 왼쪽으로 다시 순회할 때 이동거리의 최솟값을 구하는 문제이다.
이 문제는 바이토닉 투어 문제이므로 N^2 다이나믹 프로그래밍으로 해결할 수 있다.
우선 바이토닉 투어 문제는 dp[x][y]라는 테이블을 세울 수 있다. 이 때 x.는 갈 때 y는 올 때 까지 커버한 정점들의 수 이다.
점화식을 세울 때 현재 x,y까지 커버했다면 다음에 커버해야 할 정점은 당연히 max(x,y)+1이 되므로 이 정점을 갈 때 커버할 지 올 때 커버할지만 결정해주면 된다.
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 | #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int t, n; double dp[555][555]; pair<double, double> d[555]; double getdist(pair<double, double> x, pair<double, double> y) { return sqrt((x.first - y.first)*(x.first - y.first) + (x.second - y.second)*(x.second - y.second)); } double func(int x, int y) { if (x == n - 1 || y == n - 1) { if (y != n - 1)return getdist(d[y], d[n - 1]); if (x != n - 1)return getdist(d[x], d[n - 1]); return 0.0; } double &ret = dp[x][y]; if (ret != -1.0)return ret; int nxt = max(x, y) + 1; ret = 1e11; ret = min(ret, func(nxt, y) + getdist(d[x], d[nxt])); ret = min(ret, func(x, nxt) + getdist(d[y], d[nxt])); return ret; } int main() { scanf("%d", &t); while (t--) { for (int i = 0; i < 555; i++) { for (int j = 0; j < 555; j++) dp[i][j] = -1.0; } scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%lf%lf", &d[i].first, &d[i].second); printf("%.3lf\n", func(0, 0)); } return 0; } | cs |
'알고리즘 관련 > BOJ' 카테고리의 다른 글
BOJ)2104 부분배열 고르기 (0) | 2017.08.20 |
---|---|
BOJ)2872 우리집엔 도서관이 있어 (0) | 2017.08.20 |
BOJ)8462 배열의 힘 (0) | 2017.08.15 |
BOJ)3172 현주와 윤주의 재미있는 단어 게임 (0) | 2017.08.15 |
BOJ)14675 단절점과 단절선 (1) | 2017.08.06 |