• 【POJ】2449.Remmarguts' Date(K短路 n log n + k log k + m算法,非A*,论文算法)


    题解

    (搬运一个原来博客的论文题)

    抱着板题的心情去,结果有大坑
    就是S == T的时候也一定要走,++K

    我发现按照论文写得(O(n log n + m + k log k))算法没有玄学A*快,不开心啊(或者我松教水平不高啊)

    论文里主要是怎么样呢,把所有边反向,从T开始求最短路,然后求一个最短路树,求法就是把新边权改成
    原来的边权 + 终点最短路 - 起点最短路
    如果新边权是0,那么这条边就在最短路树里,如果有很多条边边权是0就随便选一条
    然后我们对于每个点走一条不同于最短路的路径,发现是走过的非树边的边权加上S到T的最短路
    我们记录每个点拓展出去的边都有哪些,拓展出去的边从小到大排序,一个点同时可以拓展它父亲可以拓展的边
    这样我们可以用一个可持久化左偏树来维护,按照左儿子右兄弟的方法扩展,删掉一个点然后把左右儿子合起来选次大,或者再从当前点走一条非树边
    不过删掉一个点把左右儿子加进去也可以

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <map>
    #include <vector>
    #include <set>
    #include <queue>
    #include <cmath>
    #define MAXN 5005
    #define PII pair<int,int>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define eps 1e-8
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    
    int N,M,St,T,K,dis[MAXN];
    vector<PII > G[MAXN],G_rev[MAXN];
    vector<int> son[MAXN];
    int fa[MAXN];
    bool vis[MAXN],ct[MAXN];
    PII line[200005];
    struct cmp1 {
        bool operator ()(const PII &a, const PII &b) {
            return a.se > b.se;
        }
    };
    
    struct Left_Tree {
        Left_Tree *lc,*rc;
        int v,to,dis;
    }pool[8000005],*tail = pool;
    vector<Left_Tree*> rt[MAXN];
    struct node {
        int s,t,cnt,v1,v0;
        friend bool operator < (const node &a,const node &b) {
            if(a.v1 != b.v1) return a.v1 < b.v1;
            else if(a.v0 != b.v0) return a.v0 < b.v0;
            else if(a.s != a.s) return a.s < b.s;
            else return a.t < b.t;
        }
    };
    multiset<node> S;
    priority_queue<PII,vector<PII >,cmp1> Q;
    Left_Tree *Newnode(PII k) {
        Left_Tree *res = tail++;
        res->v = k.se;res->to = k.fi;
        res->lc = res->rc = NULL;
        res->dis = 0;
        return res;
    }
    int get_dist(Left_Tree *r) {
        if(!r) return -1;
        else return r->dis;
    }
    Left_Tree* Merge(Left_Tree *A,Left_Tree *B) {
        if(!A) return B;
        if(!B) return A;
        if(A->v > B->v) swap(A,B);
        Left_Tree *res = tail++;
        *res = *A;
        res->rc = Merge(A->rc,B);
        if(get_dist(res->lc) < get_dist(res->rc)) swap(res->lc,res->rc); 
        res->dis = get_dist(res->rc) + 1;
        return res;
    }
    Left_Tree* build(int u,int tot) {
        if(u > tot) return NULL;
        Left_Tree *res = Newnode(line[u]);
        res->lc = build(u << 1,tot);
        res->rc = build(u << 1 | 1,tot);
        if(get_dist(res->lc) < get_dist(res->rc)) swap(res->lc,res->rc);
        res->dis = get_dist(res->lc) + 1;
        return res;
    }
    void dfs(int u) {
        int tot = 0;
        for(int i = 0 ; i < G[u].size() ; ++i) {
            PII k = G[u][i];
            if(ct[k.fi]) continue;
            if(k.se != 0 || vis[u]) {
                line[++tot] = k;
                int t = tot;
                while(t != 1) {
                    if(line[t].se < line[t >> 1].se) {
                        swap(line[t],line[t >> 1]);
                        t >>= 1;
                    }
                    else break;
                }
            }
            else vis[u] = 1;
        }
        rt[u].pb(build(1,tot));
        if(fa[u]) rt[u][0] = Merge(rt[u][0],rt[fa[u]][0]);
        for(int i = 0 ; i < son[u].size() ; ++i) dfs(son[u][i]);
    }
    void Dijkstra() {
        for(int i = 1 ; i <= N ; ++i) dis[i] = 0X7fffffff;
        dis[T] = 0;
        Q.push(mp(T,0));
        while(!Q.empty()) {
            PII u = Q.top();Q.pop();
            if(vis[u.fi]) continue;
            vis[u.fi] = 1;
            for(int i = 0 ; i < G_rev[u.fi].size() ; ++i) {
                PII k = G_rev[u.fi][i];
                if(!vis[k.fi] && u.se + k.se < dis[k.fi]) {
                    dis[k.fi] = u.se + k.se;
                    Q.push(mp(k.fi,dis[k.fi]));
                }
            }
        }
    }
    void Init() {
        scanf("%d%d",&N,&M);
        int s,t,c;
        for(int i = 1 ; i <= M ; ++i) {
            scanf("%d%d%d",&s,&t,&c);
            G[s].pb(mp(t,c));
            G_rev[t].pb(mp(s,c));
        }
        scanf("%d%d%d",&St,&T,&K);
        Dijkstra();
        for(int i = 1 ; i <= N ; ++i) {
            if(dis[i] == 0x7fffffff) {ct[i] = 1;continue;}
            for(int j = 0 ; j < G[i].size() ; ++j) {
                G[i][j].se += dis[G[i][j].fi] - dis[i];
                if(G[i][j].se == 0 && !fa[i]) {
                    fa[i] = G[i][j].fi;
                    son[fa[i]].pb(i);
                }
            }
        }
        memset(vis,0,sizeof(vis));
        dfs(T);
    }
    void Solve() {
        Init();
        if(dis[St] == 0x7fffffff) {puts("-1");return;}
        if(St == T) ++K;
        if(K == 1) {printf("%d
    ",dis[St]);return;}
        if(rt[St][0]) {
            S.insert((node){St,rt[St][0]->to,0,rt[St][0]->v,0});
        }
        int C = K - 2;
        while(C && !S.empty()) {
            C--;
            node Now = *S.begin();
            S.erase(S.begin());
            while(rt[Now.s].size() <= Now.cnt + 1) {
                int s = rt[Now.s].size() - 1;
                rt[Now.s].pb(Merge(rt[Now.s][s]->lc,rt[Now.s][s]->rc));
            }
            if(rt[Now.s][Now.cnt + 1]) {
                S.insert((node){Now.s,rt[Now.s][Now.cnt + 1]->to,Now.cnt + 1,Now.v0 + rt[Now.s][Now.cnt + 1]->v,Now.v0});
            }
            if(rt[Now.t][0]){
                S.insert((node){Now.t,rt[Now.t][0]->to,0,Now.v1 + rt[Now.t][0]->v,Now.v1});
            }
        }
        if(C || S.empty()) {
            puts("-1");
        }
        else {
            node Now = *S.begin();
            printf("%d
    ",Now.v1 + dis[St]);
        }
    }           
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    
  • 相关阅读:
    Pytorch-基于Transformer的情感分类
    Pytorch-LSTM+Attention文本分类
    .NET ------ 批量修改
    idea ---- idea中关联GitHub
    .NET ----- 将文本框改成下划线,将下拉框改为下拉下划线
    表设计(省市县)
    锁:并发编程中的三个问题(可见性、原子性、有序性)
    freemarker:常用指令、null值的处理、基本数据类型、自定义指令
    vue:绑定属性指令(绑定属性、绑定class(对象语法、数组语法))
    vue:指令(插值操作、指令(v-once、v-html、v-text、v-pre、v-cloak))
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9118074.html
Copyright © 2020-2023  润新知