[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\n", 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; 
}

谢谢阅读。

posted @ 2018-10-31 22:19  Capella  阅读(64)  评论(0编辑  收藏

谢谢光临