zoukankan      html  css  js  c++  java
  • [Luogu 2169] 正则表达式

    [Luogu 2169] 正则表达式

    <题目链接>


    感谢 0xis 推题。

    记忆中很久没有过一遍写过一题了…

    别被题目名称蒙骗!这不是正则表达式题目!和字符(串)处理一点关系都没有!这是个图论题啊喂!

    题都没急,Capella 你急啥?

    由题意得,能够本地传输的机子们处于同一强连通分量,于是 Tarjan 一遍,缩点。缩的过程中,对于两个 SCC 之间的边,选短的加。

    我这里用一个 map,记录边(pair<int, int>)到边权(int)的映射,然后用 map 判断是否加边就好了。

    最短路,跑一个 Dijkstra 即可(珍爱生命,远离某死亡算法不解释)。

    输出 1 所在的 SCC 到 n 所在的 SCC 的路径。

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <queue>
    #include <stack>
    
    #define nullptr NULL
    
    const int MAXN = 200010; 
    
    int n, m; 
    
    namespace SCC
    {
        bool exist[MAXN], vis[MAXN]; 
        int num, sum, DFN[MAXN], low[MAXN], SCC[MAXN], dist[MAXN]; 
        std :: stack<int> S; 
        struct Node
        {
            int index, dist; 
            Node(int index, int dist): index(index), dist(dist) {}
            bool operator <(const Node& rhs) const
            {
                return dist > rhs.dist; 
            }
        }; 
        struct Graph
        {
            struct Edge
            {
                int to, w; 
                Edge *next; 
                Edge(int to, int w, Edge* next): to(to), w(w), next(next) {}
                ~Edge(void)
                {
                    if(next != nullptr)
                        delete next; 
                }
            }*head[MAXN]; 
            Graph(int n)
            {
                std :: fill(head + 1, head + n + 1, (Edge*)nullptr); 
            }
            ~Graph(void)
            {
                for(int i = 1; i <= n; ++i)
                    delete head[i]; 
            }
            void AddEdge(int u, int v, int w)
            {
                head[u] = new Edge(v, w, head[u]); 
            }
        }*G, *Gnew; 
        void Tarjan(int u)
        {
            S.push(u); 
            exist[u] = true; 
            DFN[u] = low[u] = ++num; 
            int v; 
            for(Graph :: Edge *i = G -> head[u]; i != nullptr; i = i -> next)
                if(!DFN[v = i -> to])
                {
                    Tarjan(v); 
                    low[u] = std :: min(low[u], low[v]); 
                }
                else if(exist[v])
                    low[u] = std :: min(low[u], DFN[v]); 
            if(DFN[u] == low[u])
            {
                ++sum; 
                do
                {
                    exist[v = S.top()] = false; 
                    S.pop(); 
                    SCC[v] = sum; 
                }
                while(u ^ v); 
            }
        }
        void Shrink(void)
        {
            std :: map<std :: pair<int, int>, int> QAQ; 
            std :: pair<int, int> t; 
            Gnew = new Graph(sum); 
            for(int u = 1, v; u <= n; ++u)
                for(Graph :: Edge *i = G -> head[u]; i != nullptr; i = i -> next)
                    if(!QAQ.count(t = std :: make_pair(SCC[u], SCC[v = i -> to])) || i -> w < QAQ[t])
                    {
                        Gnew -> AddEdge(SCC[u], SCC[v], i -> w); 
                        QAQ[t] = i -> w; 
                    }
        }
        void Dijkstra(int S)
        {
            std :: priority_queue<Node> Q; 
            memset(dist, 0x3f, sizeof dist); 
            Q.push(Node(S, dist[S] = 0)); 
            while(!Q.empty())
            {
                int u = Q.top().index, v; 
                Q.pop(); 
                if(!vis[u])
                {
                    vis[u] = true; 
                    for(Graph :: Edge *i = Gnew -> head[u]; i != nullptr; i = i -> next)
                        if(dist[v = i -> to] > dist[u] + i -> w)
                            Q.push(Node(v, dist[v] = dist[u] + i -> w)); 
                }
            }
        }
        void Solve(void)
        {
            for(int i = 1; i <= n; ++i)
                if(!DFN[i])
                    Tarjan(i); 
            Shrink(); 
            Dijkstra(SCC[1]); 
            printf("%d
    ", dist[SCC[n]]); 
        }
    }
    
    int main(void)
    {
        scanf("%d %d", &n, &m); 
        SCC :: G = new SCC :: Graph(n); 
        for(int i = 1, u, v, w; i <= m; ++i)
        {
            scanf("%d %d %d", &u, &v, &w); 
            SCC :: G -> AddEdge(u, v, w); 
        }
        SCC :: Solve(); 
        return 0; 
    }
    

    谢谢阅读。

  • 相关阅读:
    BZOJ 2594: [Wc2006]水管局长数据加强版
    BZOJ 2049: [Sdoi2008]Cave 洞穴勘测
    html5 canvas ( 贝塞尔曲线, 一片星空加绿地 ) quadraticCurveTo, bezierCurveTo
    c#.net 接收 base64 格式的数据并解析为图片
    html5 canvas ( 绘制一轮弯月, 星空中的弯月 )
    html5 canvas ( 圆和切点曲线的绘制 ) arc, arcTo
    html5 canvas ( 图片填充样式 ) fillStyle, createPattern
    html5 canvas ( 径向渐变, 升级版的星空 ) fillStyle, createRadialGradient
    html5 canvas ( 线性渐变, 升级版的星空 ) fillStyle, createLinearGradient, addColorStop
    html5 canvas ( 图形变换矩阵 ) transform, setTransform
  • 原文地址:https://www.cnblogs.com/Capella/p/9886301.html
Copyright © 2011-2022 走看看