【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; }