bzoj4152 [AMPPZ2014]The Captain
4152: [AMPPZ2014]The Captain
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1293 Solved: 502
[Submit][Status][Discuss]
Description
给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用。
Input
第一行包含一个正整数n(2<=n<=200000),表示点数。
接下来n行,每行包含两个整数x[i],y[i](0<=x[i],y[i]<=10^9),依次表示每个点的坐标。
Output
一个整数,即最小费用。
Sample Input
5
2 2
1 1
4 5
7 1
6 7
2 2
1 1
4 5
7 1
6 7
Sample Output
2
HINT
Source
分析:这道题最关键的一点就是如何建图,如果每两个点都连一条边,那么空间会直接炸掉,考虑哪些边不用连.如果两个点之间有中间点的话,一定是走中间点的!这个可以非常容易证明,那么我们先按照x排序,再按照y排序,只在相邻点之间连边就好了.
不过这道题卡spfa,用dijkstra就是稳定的O(nlogn)了,不会超时.
如果建边是最短路问题的考点,那么先考虑能不能有一个只进不出和一个只出不进的中间点,如果不行,看建边的点是不是区间的形式,如果还不行,就要分析问题,看能不能删掉某些边.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> using namespace std; const int maxn = 200010; const long long inf = 1000000000000000; struct node { int x,y,id; }e[200010]; struct node2 { int x; long long len; }; bool operator < (node2 a,node2 b) { return a.len > b.len; } int n,head[maxn],to[maxn * 4],nextt[maxn * 4],tot = 1,w[maxn * 4],vis[maxn * 4]; priority_queue <node2> q; long long d[maxn]; bool cmp1(node a,node b) { return a.x < b.x; } bool cmp2(node a,node b) { return a.y < b.y; } void add(int x,int y,int z) { w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void dijkstra() { for (int i = 1; i <= n; i++) d[i] = inf; d[1] = 0; node2 temp; temp.len = 0; temp.x = 1; q.push(temp); while (!q.empty()) { while (!q.empty() && vis[q.top().x]) q.pop(); if (q.empty()) return; node2 u = q.top(); q.pop(); int x = u.x; long long len = u.len; vis[x] = 1; for (int i = head[x]; i;i = nextt[i]) { int v = to[i]; if (d[v] > d[x] + w[i]) { d[v] = d[x] + w[i]; node2 temp; temp.x = v; temp.len = d[v]; q.push(temp); } } } } int main() { scanf("%d",&n); for (int i = 1; i <= n; i++) { scanf("%d%d",&e[i].x,&e[i].y); e[i].id = i; } sort(e + 1,e + 1 + n,cmp1); for (int i = 1; i < n; i++) { int t = min(abs(e[i].x - e[i + 1].x),abs(e[i].y - e[i + 1].y)); add(e[i].id,e[i + 1].id,t); add(e[i+1].id,e[i].id,t); } sort(e + 1,e + 1 + n,cmp2); for (int i = 1; i < n; i++) { int t = min(abs(e[i].x - e[i + 1].x),abs(e[i].y - e[i + 1].y)); add(e[i].id,e[i + 1].id,t); add(e[i+1].id,e[i].id,t); } dijkstra(); printf("%lld\n",d[n]); return 0; }