BZOJ 4152 浅谈堆优化的SPFA算法

BZOJ 4152 浅谈堆优化的SPFA算法_第1张图片
世界真的很大
其实这道题一看就能想到最短路
关键是怎么建边
看一下数据,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
#include
#include
#include
#include
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 < pairint> ,vector< pairint> > ,greaterint> > > state;

bool cmp1(const point &a,const point &b)
{
    return a.xbool cmp2(const point &a,const point &b)
{
    return a.ybool cmp3(const point &a,const point &b)
{
    return a.idxvoid 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;i1].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;i1].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; 
}

嗯,就是这样

你可能感兴趣的:(最短路)