2015山东信息学夏令营 Day5T3 路径
问题描述:
给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用。
输入:
第一行包含一个正整数n,表示点数。
接下来n行,每行包含两个整数x[i],y[i](0<=x[i],y[i]<=10^9),依次表示每个点的坐标。
输出:
一个整数,即最小费用。
输入输出样例:
path.in |
path.out |
5 |
2
|
数据范围:
对于30%的数据,1<=n<=100;
对于60%的数据,1<=n<=1000;
对于全部的数据,1<=n<=200000;
思路:
1、60分直接最短路
2、对于坐标系中连续的三个点,(x1,y1),(x2,y2),(x3,y3),总有min(x2-x1,y2-y1) + min(x3-x2,y3-y2) ≤ min(x3 - x1,y3 - y1),所以在建图的时候,可以按x,y分别排一遍序,然后,相邻的点建边,这样边数为2*n,再用堆dij就可以了
代码:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<queue> #define maxn 200005 #define inf ~0U>>1 using namespace std; struct point{ int x; int y; int pos; }; struct orz{ int p; int d; friend bool operator < (orz a,orz b){ return a.d > b.d; } }; struct edge{ int v; int w; }; priority_queue< orz > ss; vector<edge> g[maxn]; point pt[maxn]; int flag = 0,v[maxn],d[maxn],n; bool cmpa(point a,point b){ return a.x < b.x; } bool cmpb(point a,point b){ return a.y < b.y; } void init(){ cin>>n; int tx,ty; for(int i = 1;i <= n;i++){ scanf("%d%d",&tx,&ty); pt[i].x = tx; pt[i].y = ty; pt[i].pos = i; } for(int i = 1;i <= n;i++) d[i] = inf; sort(pt+1,pt+1+n,cmpa); edge tmp; for(int i = 1;i < n;i++){ tmp.w = pt[i+1].x - pt[i].x; tmp.v = pt[i + 1].pos; g[pt[i].pos].push_back(tmp); tmp.v = pt[i].pos; g[pt[i+1].pos].push_back(tmp); } sort(pt+1,pt+1+n,cmpb); for(int i = 1;i < n;i++){ tmp.w = pt[i+1].y - pt[i].y; tmp.v = pt[i + 1].pos; g[pt[i].pos].push_back(tmp); tmp.v = pt[i].pos; g[pt[i+1].pos].push_back(tmp); } } void dij(){ orz tmp; d[1] = 0; tmp.p = 1; tmp.d = 0; ss.push(tmp); flag++; int to,wei,x,dd; edge j; while(!ss.empty()){ tmp = ss.top(); ss.pop(); x = tmp.p; dd = tmp.d; if(v[x] == flag) continue; v[x] = flag; for(int i = 0;i < g[x].size();i++){ j = g[x][i]; to = j.v; wei = j.w; if(d[to] > dd + wei){ d[to] = dd + wei; tmp.d = dd + wei; tmp.p = to; ss.push(tmp); } } } cout<<d[n]; } int main(){ init(); dij(); return 0; }