首页 > 代码库 > BZOJ 1975 SDOI2010 魔法猪学院 A*k短路

BZOJ 1975 SDOI2010 魔法猪学院 A*k短路

题目大意:给定一个值E 求起点到终点的最多条路径 使长度之和不超过E

k短路的A*算法……每个点有一个估价函数=g[x]+h[x] 其中g[x]是从源点出发已经走了的长度 h[x]是从这个点到汇点的最短路

首先先在反图上跑一遍SPFA求出每个点的h[x],然后将源点的g[x]+h[x]加入堆 每次取出堆顶时将堆顶的g[x]向所连接的边扩展 第k次取出汇点即是答案

其中有一个剪枝就是当第k+1次取出某个点时不继续拓展 防止MLE 但是这里k未知 我们可以对k进行估价处理 初始k=floor(E/最短路长度) 然后每次取出汇点时更新k k=cnt[n]+floor(E/当前路径长度)

比较丧病的是这题卡priority_queue……这东西的内存是手写堆的二倍 由于卡内存 所以会挂 可以手写堆 我写了可并堆+垃圾回收……

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 5050
using namespace std;
struct abcd{
    int pos;
    double g,h;
    bool operator < (const abcd &x) const
    {
        return g + h < x.g + x.h ;
    }
};
struct Heap{
    abcd num;
    Heap *ls,*rs;
    void* operator new (size_t size,int pos,double g,double h);
    void operator delete (void* p);
}*root,*mempool,*C;
struct edge{
    int to,next;
    double f;
}table[400400];
int head[M],tot=1;
bool flag;
queue<void*> bin;
int n,m,k,ans,cnt[M];
double e,f[M];
void* Heap :: operator new (size_t size,int pos,double g,double h)
{
    if( !bin.empty() )
    {
        Heap *re=(Heap*)bin.front();
        bin.pop();
        re->num.pos=pos;
        re->num.g=g;
        re->num.h=h;
        re->ls=re->rs=0x0;
        return re;
    }
    if(C==mempool)
    {
        C=new Heap[1<<15];
        mempool=C+(1<<15);
    }
    C->num.pos=pos;
    C->num.g=g;
    C->num.h=h;
    C->ls=C->rs=0x0;
    return C++;
}
void Heap :: operator delete (void *p)
{
    bin.push(p);
}
Heap* Merge(Heap *x,Heap *y)
{
    if(!x) return y;
    if(!y) return x;
    if( y->num < x->num )
        swap(x,y);
    if(flag^=1)
        x->ls=Merge(x->ls,y);
    else
        x->rs=Merge(x->rs,y);
    return x;
}
inline void Insert(int pos,double g,double h)
{
    root=Merge(root,new (pos,g,h) Heap);
}
inline void Pop()
{
    delete root;
    root=Merge(root->ls,root->rs);
}
void Add(int x,int y,double z)
{
    table[++tot].to=y;
    table[tot].f=z;
    table[tot].next=head[x];
    head[x]=tot;
}
void SPFA()
{
    static int q[1<<16];
    static unsigned short r,h;
    static bool v[M];
    int i;
    memset(f,0x42,sizeof f);
    f[n]=0;q[++r]=n;
    while(r!=h)
    {
        int x=q[++h];v[x]=0;
        for(i=head[x];i;i=table[i].next)
            if( i&1 && f[table[i].to]>f[x]+table[i].f )
            {
                f[table[i].to]=f[x]+table[i].f;
                if(!v[table[i].to])
                    v[table[i].to]=1,q[++r]=table[i].to;
            }
    }
}
void A_Star()
{
    int i;
    k=static_cast<int>(e/f[1])+1;
    Insert(1,0,f[1]);
    while(root)
    {
        abcd x=root->num;Pop();
        if( ++cnt[x.pos]>k )
            continue;
        if(x.pos==n)
        {
            if(e-x.g<0) return ;
            e-=x.g;++ans;
            k=cnt[n]+static_cast<int>(e/x.g)+1;
        }
        for(i=head[x.pos];i;i=table[i].next)
            if(~i&1)
                Insert(table[i].to,x.g+table[i].f,f[table[i].to]);
    }
}
int main()
{
    int i,x,y;
    double z;
    cin>>n>>m>>e;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%lf",&x,&y,&z);
        Add(x,y,z);
        Add(y,x,z);
    }
    SPFA();
    A_Star();
    cout<<ans<<endl;
    return 0;
}


BZOJ 1975 SDOI2010 魔法猪学院 A*k短路