[题解] [BZOJ4152] The Captain
题面
题解
将所有点根据𝑥排序后, 相邻的连一条双向边
正确性: 若对于两个点的𝑑𝑖𝑠是由𝑥来更新, 则𝑑𝑖𝑠会等于中间所有点之间相邻的边的和
如果是由𝑦更新呢?
再根据𝑦排序后, 相邻的连边即可
代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define mk(i, j) make_pair(i, j)
#define N 200005
using namespace std;
int n, head[N], cnt;
long long dis[N];
bool vis[N];
struct node { int x, y, id; } p[N];
struct edge { int to, next; long long cost; } e[N << 2];
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
inline void adde(int u, int v, long long w)
{
e[++cnt] = (edge) { v, head[u], w }; head[u] = cnt;
e[++cnt] = (edge) { u, head[v], w }; head[v] = cnt;
}
bool cmp1(node x, node y) { return x.x < y.x; }
bool cmp2(node x, node y) { return x.y < y.y; }
int dijkstra()
{
priority_queue<pair <int, int > > q;
memset(dis, 0x3f, sizeof(dis));
dis[1] = 0; q.push(mk(dis[1], 1));
while(!q.empty())
{
int u = q.top().second; q.pop();
vis[u] = 1;
for(int v, i = head[u]; i; i = e[i].next)
{
v = e[i].to;
if(dis[v] > dis[u] + e[i].cost && !vis[v])
{
dis[v] = dis[u] + e[i].cost;
q.push(mk(-dis[v], v));
}
}
}
return dis[n];
}
int main()
{
n = read <int> ();
for(int i = 1; i <= n; i++)
p[i].x = read <int> (), p[i].y = read <int> (), p[i].id = i;
sort(p + 1, p + n + 1, cmp1);
for(int i = 1; i < n; i++)
adde(p[i].id, p[i + 1].id, p[i + 1].x - p[i].x);
sort(p + 1, p + n + 1, cmp2);
for(int i = 1; i <= n; i++)
adde(p[i].id, p[i + 1].id, p[i + 1].y - p[i].y);
printf("%d\n", dijkstra());
return 0;
}