1. 程式人生 > >【BZOJ4152】The Captain

【BZOJ4152】The Captain

題目連結:https://www.lydsy.com/JudgeOnline/problem.php?id=4152


 

貪心+最短路吧,如果兩點之間存在一個拐點,那麼經過掛點一定不會比直接到達差,這個很容易想象,因此,我們應將橫縱座標分別排序,將相鄰的橫縱座標之間建邊。

細節也不多,本題的關鍵就是如何巧妙地建邊,而不是建n^2條邊。哦,據說題目卡了SPFA,和我又有啥關係呢。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using
namespace std; inline int get_num() { int num = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') num = num * 10 + c - '0', c = getchar(); return num; } const int maxn = 2e5 + 5, inf = 0x3f3f3f3f;
int head[maxn], eid; struct Edge { int v, w, next; } edge[4 * maxn]; inline void insert(int u, int v, int w) { edge[++eid].v = v; edge[eid].w = w; edge[eid].next = head[u]; head[u] = eid; } inline void insert2(int u, int v, int w) { insert(u, v, w); insert(v, u, w); }
int dist[maxn], vis[maxn]; struct node { int id, dist; node(int i, int d) : id(i), dist(d) {} bool operator < (const node& rhs) const { return dist > rhs.dist; } }; priority_queue<node> q; inline void dijkstra() { memset(dist, inf, sizeof(dist)); dist[1] = 0; q.push(node(1, 0)); while (!q.empty()) { int u = q.top().id; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int p = head[u]; p; p = edge[p].next) { int v = edge[p].v, w = edge[p].w; if (dist[v] > dist[u] + w) { dist[v] = dist[u] + w; q.push(node(v, dist[v])); } } } } struct Point { int id, x, y; } point[maxn]; bool comp1(const Point& lhs, const Point& rhs) { return lhs.x < rhs.x; } bool comp2(const Point& lhs, const Point& rhs) { return lhs.y < rhs.y; } int main() { int n = get_num(); for (int i = 1; i <= n; ++i) point[i].id = i, point[i].x = get_num(), point[i].y = get_num(); sort(point + 1, point + n + 1, comp1); for (int i = 2; i <= n; ++i) insert2(point[i - 1].id, point[i].id, point[i].x - point[i - 1].x); sort(point + 1, point + n + 1, comp2); for (int i = 1; i <= n; ++i) insert2(point[i - 1].id, point[i].id, point[i].y - point[i - 1].y); dijkstra(); printf("%d", dist[n]); return 0; }
AC程式碼