「BZOJ 1975」[SDOI2010]魔法猪学院

Description

k 短路,最短路+可持久化可并堆 O ( m log m + k log k + n log m )
又是一道论文题。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

#ifdef DEBUG
    #define debug(orz...) printf(orz)
    #define yes(orz...) puts(orz)
#else 
    #define debug(...) 0
    #define yes(...) 0
#endif

#define Min(_A, _B) (_A < _B ? _A : _B)
#define Abs(_A) (_A > 0 ? _A : -(_A))
#define R register
#define Null b
int F()
{
    R int x; R char ch;
    while(ch = getchar(), ch < '0' || ch > '9'); x = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - '0';
    return x;
}

const int MaxN = 5010, MaxM = 200010;

int N, M; double E;
struct Edge{ int u, v; double w; } e[MaxM];
int Point[MaxN], Next[MaxM], To[MaxM], q, fa[MaxN]; double W[MaxM];
void Add(R int u, R int v, double w){ Next[++q] = Point[u]; Point[u] = q; To[q] = v; W[q] = w; }
void Add(R int u, R int v){ Next[++q] = Point[u]; Point[u] = q; To[q] = v; }
struct CMP{ int i; double dis; bool operator < (const R CMP i) const { return dis > i.dis; }};
std::priority_queue<CMP> Q;
double dis[MaxN]; bool vis[MaxN], used[MaxM];
void dfs(R int u)
{
    vis[u] = 1;
    for(R int j = Point[u]; j; j = Next[j])
        if(!vis[To[j]] && Abs(dis[To[j]] - W[j] - dis[u]) < 1e-9)
        {
            fa[To[j]] = u; used[j] = 1;
            dfs(To[j]);
        }
}
void Dij()
{
    Q.push((CMP){N, 0});
    for(R int i = 1; i <= N; ++i) dis[i] = 1e9;
    while(!Q.empty())
    {
        while(!Q.empty() && vis[Q.top().i]) Q.pop();
        if(Q.empty()) break;
        R CMP t = Q.top(); Q.pop();
        vis[t.i] = 1; dis[t.i] = t.dis;
        for(R int j = Point[t.i]; j; j = Next[j])
            if(!vis[To[j]] && dis[t.i] + W[j] < dis[To[j]])
                Q.push((CMP){To[j], dis[To[j]] = dis[t.i] + W[j]});
    }
    memset(vis, 0, sizeof(vis));
    dfs(N);
    memset(Point, 0, sizeof(Point)); q = 0;
    for(R int i = 1; i < N; ++i) Add(fa[i], i);
}

struct Data{ double val; int pos, dis; Data *lson, *rson; } b[300010], *root[MaxN]; int tot;
Data *Merge(Data *A, Data *B)
{
    if(A == Null || B == Null) return A == Null ? B : A;
    if(A->val > B->val) std::swap(A, B);
    A->rson = Merge(A->rson, B);
    if(A->rson->dis > A->lson->dis) std::swap(A->rson, A->lson);
    A->dis = A->rson->dis + 1;
    return A;
}
Data *PMerge(Data *&A, Data *&B)
{
    if(A == Null || B == Null) return A == Null ? B : A;
    Data *t = b + ++tot, *res;
    if(A->val < B->val){ *t = *A; res = B; }
    else { *t = *B; res = A; }
    t->rson = PMerge(t->rson, res);
    if(t->rson->dis > res->lson->dis) std::swap(t->rson, t->lson);
    t->dis = t->rson->dis + 1;
    return t;
}
void Push(Data *&A, R int pos, R double val)
{
    b[++tot] = b[0];
    Data *t = b + tot; t->pos = pos; t->val = val;
    A = Merge(A, t);
}
void Pop(Data *&A){ A = PMerge(A->lson, A->rson); }
void DFS(R int u)
{
    for(R int j = Point[u]; j; j = Next[j])
    {
        root[To[j]] = PMerge(root[To[j]], root[u]);
        DFS(To[j]);
    }
}
struct Tmp{ Data *pos; double dis, val; bool operator < (const R Tmp i) const{ return dis > i.dis; }};
std::priority_queue<Tmp> V;
void solve()
{
    R int k = 1; E -= dis[1];
    if(root[1] != Null) V.push((Tmp){root[1], dis[1] + root[1]->val, root[1]->val});
    while(!V.empty())
    {
        R Tmp t = V.top(); V.pop();
        E -= t.dis;
        if(E > -1e-9) ++k; 
        else break;
        if(t.dis - t.val + t.pos->val <= E)
        {
            if(root[t.pos->pos] != Null) 
                V.push((Tmp){root[t.pos->pos], t.dis + root[t.pos->pos]->val, root[t.pos->pos]->val});
            if(t.pos->lson != Null) 
                V.push((Tmp){t.pos->lson, t.dis - t.val + t.pos->lson->val, t.pos->lson->val});
            if(t.pos->rson != Null) 
                V.push((Tmp){t.pos->rson, t.dis - t.val + t.pos->rson->val, t.pos->rson->val});
        }
    }
    printf("%d\n", k);
}
int main()
{
    b[0] = (Data){0, 0, -1, Null, Null};
    scanf("%d %d %lf", &N, &M, &E);
    for(R int i = 1; i <= M; ++i)
    {
        R int s = F(), t = F(); R double w;
        scanf("%lf", &w);
        if(s == N){ --i; --M; continue; }
        e[i] = (Edge){s, t, w};
        Add(t, s, w);
    }
    Dij();
    for(R int i = 1; i <= N; ++i) root[i] = Null;
    for(R Edge *i = e + 1; i <= e + M; ++i) if(!used[i - e])
        Push(root[i->u], i->v, dis[i->v] - dis[i->u] + i->w);
    DFS(N);
    solve();
    return 0;
}

A*算法,然而早期写的,写的太差,BZOJ 上被卡空间了,luogu 80+分,复杂度 O ( n k )

#include <cstdio>
#include <queue>
#include <cstring>
#define R register
const int MaxN = 5010, MaxM = 200010;
int N, M; double E;
int Point[MaxN], Next[MaxM << 1], To[MaxM << 1], q = 1;
double W[MaxM << 1];
void Add(R int u, R int v, R double w)
{
    Next[++q] = Point[u]; Point[u] = q; To[q] = v; W[q] = w;
    Next[++q] = Point[v]; Point[v] = q; To[q] = u; W[q] = w;
}
bool vis[MaxN]; int f[MaxN]; double dis[MaxN];
void SPFA()
{
    R int head = 0, tail = 1;
    for(R int i = 1; i <= N; i++) dis[i] = 100000000;
    f[1] = N; vis[N] = 1; dis[N] = 0;
    do
    {
        head = ++head % MaxN;
        for(R int j = Point[f[head]]; j; j = Next[j])
        {
            if((j & 1) && dis[To[j]] > dis[f[head]] + W[j])
            {
                dis[To[j]] = dis[f[head]] + W[j];
                if(!vis[To[j]]) vis[f[tail = ++tail % MaxN] = To[j]] = 1;
            }
        }
        vis[f[head]] = 0;
    }
    while(head != tail);
}
double s[MaxN]; int Ans;
struct Data
{
    double g, h;
    int Pos;
    bool operator < (Data i) const
    {
        return h > i.h;
    }
    bool operator > (Data i) const 
    {
        return h < i.h;
    }
};
std::priority_queue<Data> A;
void A_Star()
{
    A.push((Data){0, dis[1], 1});
    do
    {
        R Data t = A.top(); A.pop();
        if(t.Pos == N) E -= t.g, Ans++;
        if(E < 0) return ;
        for(R int j = Point[t.Pos]; j; j = Next[j])
            if(!(j & 1)) 
                A.push((Data){t.g + W[j], t.g + W[j] + dis[To[j]], To[j]});
    }
    while(!A.empty());
}
int main()
{
    scanf("%d %d %lf", &N, &M, &E);
    for(R int i = 1; i <= M; i++)
    {
        R int s, t; double e;
        scanf("%d %d %lf", &s, &t, &e);
        Add(s, t, e);
    }
    SPFA();
    A_Star();
    printf("%d", Ans - 1);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/steaunk/article/details/80094904