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 2
1 1
4 5
7 1
6 7

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

 

posted @ 2016-08-26 21:30  ACforever  阅读(268)  评论(0编辑  收藏  举报