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; 
    }
    

    谢谢阅读。

  • 相关阅读:
    Csharp: create Transparent Images in winform
    HTML5:Subway Map Visualization jQuery Plugin(示例畫深圳地鐵線路圖)
    sql 语句 查询 sql server 主键!
    面向对象学习
    聚类算法学习笔记(一)——基础
    oracle 会话以及处理数
    java.util.Calendar常量字段值
    java连接sql时候,获取表格各列属性
    Oracle 动态SQL返回单条结果和结果集
    Oracle数据库数据字典学习
  • 原文地址:https://www.cnblogs.com/Capella/p/9886301.html
Copyright © 2011-2022 走看看