BZOJ 4152 浅谈堆优化的SPFA算法

来源:互联网 发布:java程序员兼职 编辑:程序博客网 时间:2024/06/15 11:04

这里写图片描述
世界真的很大
其实这道题一看就能想到最短路
关键是怎么建边
看一下数据,200000个点
每个点两两建边的话肯定会超时
好像说多了先看一下题吧:
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

一个整数,即最小费用。

首先是最短路没错了
关键是考虑一下怎么建边
认真看一下题
对每一个点来说,想要到它无非两种方法,通过x或y。换个角度想,从一个点到任意另一个点,直接通过距离的费用肯定大于等于通过x或y相邻的点搭桥过去
因为直接过去是直接x坐标或y坐标的距离,但是间接过去是去中间的点的x,y距离的较小值相加。
所以每个点和多余的点建边其实没什么意义,只用和与自己在x,y相邻的点建边就行了。
那么排个序,挨个建边,跑最短路,KO
还有一个坑点,这道题卡SPFA
SPFA对于稠密图效率很低,不如dijkstra
但是它真的能逼我去写dijkstra吗???
答案是否定的
dijkstra可以堆优化,spfa一样可以。其实说是堆,我大概也不会真的手写堆吧。。。
STL里有一个优先队列priority_queue非常好用,作为一个队列可以logn维护队列有序,经常被当做堆使用。
大根堆的话直接用就行,小根堆的话就需要加一个:

priority_queue<int,vector<int>,greater<int> > xiao;

详细的话就看完整代码吧:

#include<stdio.h>#include<cstring>#include<queue>#include<map>#include<algorithm>using namespace std;typedef long long dnt;struct point{    int x,y,idx;}pt[1000010];struct edge{    int last,v,w;}ed[1000010];int num=0,n;int  se[500010],head[500010];dnt dis[500010],INF=1e14+7LL;priority_queue < pair<dnt,int> ,vector< pair<dnt,int> > ,greater<pair<dnt,int> > > state;bool cmp1(const point &a,const point &b){    return a.x<b.x;}bool cmp2(const point &a,const point &b){    return a.y<b.y;}bool cmp3(const point &a,const point &b){    return a.idx<b.idx;}void add(int u,int v,int w){    num++;    ed[num].v=v;    ed[num].w=w;    ed[num].last=head[u];    head[u]=num;}void spfa(){    for(int i=1;i<=n;i++) dis[i]=INF;    state.push(make_pair(0,1));    se[1]=1,dis[1]=0;    while(!state.empty())    {        int u=state.top().second;        state.pop();        se[u]=0;        for(int i=head[u];i;i=ed[i].last)        {            int v=ed[i].v;            if(dis[v]>dis[u]+ed[i].w)            {                dis[v]=dis[u]+ed[i].w;                if(!se[v])                {                    se[v]=1;                    state.push(make_pair(dis[v],v));                }            }        }    }}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d%d",&pt[i].x,&pt[i].y);        pt[i].idx=i;    }    sort(pt+1,pt+n+1,cmp1);    for(int i=1;i<n;i++)    {        add(pt[i].idx,pt[i+1].idx,pt[i+1].x-pt[i].x);        add(pt[i+1].idx,pt[i].idx,pt[i+1].x-pt[i].x);    }    sort(pt+1,pt+n+1,cmp2);    for(int i=1;i<n;i++)    {        add(pt[i].idx,pt[i+1].idx,pt[i+1].y-pt[i].y);        add(pt[i+1].idx,pt[i].idx,pt[i+1].y-pt[i].y);    }    spfa();    printf("%lld",dis[n]);    return 0; }

嗯,就是这样