[题解] [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; 
}
posted @ 2019-11-06 17:18  ztlztl  阅读(119)  评论(0编辑  收藏  举报