• 仙人掌


    任意一条边至多只出现在一条简单回路的无向连通图称为仙人掌

    求仙人掌的最短路

    大致做法:利用类似tarjan的方式将一个环缩到一起,建立圆方树,对于一个环找到头节点,建立一个方点,头节点向方点连一条权值为0的边,方点向环上的点再连一条权值为该点到头节点最短距离的边

    然后再树上找最短路就是找到lca然后类似前缀和相减的方式,对于lca找到的如果方点需要特殊处理---把这个圆取一下两个点之间的最短距离

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 12010, M = N * 3;
    
    int n, m, Q, new_n;
    int h1[N], h2[N], e[M], w[M], ne[M], idx;
    int dfn[N], low[N], cnt;
    int s[N], stot[N], fu[N], fw[N];
    int fa[N][14], depth[N], d[N];
    int A, B;
    
    void add(int h[], int a, int b, int c)
    {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    void build_circle(int x, int y, int z)
    {
        int sum = z;
        for (int k = y; k != x; k = fu[k])
        {
            s[k] = sum;
            sum += fw[k];
        }
        s[x] = stot[x] = sum;
        add(h2, x, ++ new_n, 0);
        for (int k = y; k != x; k = fu[k])
        {
            stot[k] = sum;
            add(h2, new_n, k, min(s[k], sum - s[k]));
        }
    }
    
    void tarjan(int u, int from)
    {
        dfn[u] = low[u] = ++ cnt;
        for (int i = h1[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if (!dfn[j])
            {
                fu[j] = u, fw[j] = w[i];
                tarjan(j, i);
                low[u] = min(low[u], low[j]);
                if (dfn[u] < low[j]) add(h2, u, j, w[i]);
            }
            else if (i != (from ^ 1)) low[u] = min(low[u], dfn[j]);
        }
        for (int i = h1[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if (dfn[u] < dfn[j] && fu[j] != u)
                build_circle(u, j, w[i]);
        }
    }
    
    void dfs_lca(int u, int father)
    {
        depth[u] = depth[father] + 1;
        fa[u][0] = father;
        for (int k = 1; k <= 13; k ++ )
            fa[u][k] = fa[fa[u][k - 1]][k - 1];
        for (int i = h2[u]; ~i; i = ne[i])
        {
            int j = e[i];
            d[j] = d[u] + w[i];
            dfs_lca(j, u);
        }
    }
    
    int lca(int a, int b)
    {
        if (depth[a] < depth[b]) swap(a, b);
        for (int k = 13; k >= 0; k -- )
            if (depth[fa[a][k]] >= depth[b])
                a = fa[a][k];
        if (a == b) return a;
        for (int k = 13; k >= 0; k -- )
            if (fa[a][k] != fa[b][k])
            {
                a = fa[a][k];
                b = fa[b][k];
            }
        A = a, B = b;
        return fa[a][0];
    }
    
    int main()
    {
        scanf("%d%d%d", &n, &m, &Q);
        new_n = n;
        memset(h1, -1, sizeof h1);
        memset(h2, -1, sizeof h2);
        while (m -- )
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(h1, a, b, c), add(h1, b, a, c);
        }
        tarjan(1, -1);
        dfs_lca(1, 0);
    
        while (Q -- )
        {
            int a, b;
            scanf("%d%d", &a, &b);
            int p = lca(a, b);
            if (p <= n) printf("%d
    ", d[a] + d[b] - d[p] * 2);
            else
            {
                int da = d[a] - d[A], db = d[b] - d[B];
                int l = abs(s[A] - s[B]);
                int dm = min(l, stot[A] - l);
                printf("%d
    ", da + dm + db);
            }
        }
    
        return 0;
    }
    

      

  • 相关阅读:
    RabbitMQ一:消息队列的认识
    RabbitMQ二:AMQP协议
    SVN中如何去除版本控制器
    Asp.net:MVC认识
    时间连接查询展示
    C#string类型总结
    JavaScript01天学习笔记分享
    UML中的类图及类图之间的关系
    23 种设计模式的分类和功能
    WCF入门
  • 原文地址:https://www.cnblogs.com/cyq123/p/14230834.html
Copyright © 2020-2023  润新知