[Luogu P3387] condensing point template (strongly connected component Tarjan & topological sort)

Luogu P3387
strongly connected component is defined as follows:

Tuqiang connected component directed: in a directed graph G, if two vertices vi, vj between (vi> vj) from vi to vj there is a directed path, as well as one from vi to vj directional path , called two vertices strongly connected (strongly connected). If there are strongly connected to each of the two vertices of G, said G is a strongly connected graph. There are a great strength to FIG connected subgraph, called strongly connected components (strongly connected components).

From Baidu Encyclopedia

My own understanding: There has to be called this a strongly connected component (which can also be said to be a ring) can not expand to a larger strongly connected subgraph again in Figure
Note: a single isolated point will It is a strongly connected component
after strongly connected components obtained what use is it?
Obviously, we can put the entire strongly connected component as a single point, the weights in accordance with the subject request access (in this problem is to take the sum of all points right), so you can make this one has to have a ring of FIG transformed into a directed acyclic graph.

Tarjan algorithm

Tarjan algorithm (referred to herein as the algorithm for strongly connected components Tarjan forth) is used for efficient algorithms to all strongly connected components in a graph is obtained.
The basic idea is to use DFS search down marker sequence, if found to return an ancestor edge, then constitute a ring (strongly connected components).
Here to introduce a few necessary Tarjan algorithm array

Array name effect
dfn[i] Recording a sequence of node i dfs
paragraph [i] A stack for recording the node on which one strand of the current search
low[i] Recording node for node i to access the smallest dfs sequence, i.e. uppermost ancestor

Key point: If dfn [i] == low [i ], means that no node has access to the ancestor node i in the sub-tree node i, the description still poses a node i and in the sub-stack node (necessary condition) a strongly connected component
is not a child node in the stack can not be strongly connected components constituting the node i, then the reason is not within the stack is popped off the stack itself has a strongly connected component as a.

void tarjan(int now)
{
    dfn[now]=++tim;//记录dfs序
    low[now]=tim;//当前能访问到dfs序最小的点就是自己
    stk[++cnt]=now;
    vis[now]=true;
    for (int i=head[now];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if (!dfn[to])
        {
            tarjan(to);
            low[now]=min(low[now],low[to]);
            //如果该点没被遍历过,那么就进行遍历。
        }
        else 
        {
            if (vis[to]) low[now]=min(low[now],dfn[to]);
            //必须判断是否在栈中。只有在同时在栈内的点才有可能构成强连通分量。
        }
    }
    if (low[now]==dfn[now])
    {
        tot++;//强连通分量的编号
        while (stk[cnt]!=now)
        {
            scc[stk[cnt]]=tot;
            val[tot]+=a[stk[cnt]];
            vis[stk[cnt]]=false;
            cnt--;
        }
        scc[stk[cnt]]=tot;
        val[tot]+=a[stk[cnt]];
        vis[stk[cnt]]=false;
        cnt--;
        //将栈中比u后进入的点和u本身出栈,这些点构成一个强联通分量,打上标记
    }
}

It is understood in conjunction with the code.

Condensing point operation topological sorting and

For a directed acyclic graph (Directed Acyclic Graph referred to as the DAG) G be topologically sorted, all the vertices of G is arranged in a linear sequence, such that any pair of vertices FIG u and v, if the edge <u, v> ∈ E (G), the linear sequence u appears before v. Typically, such a sequence is called a linear sequence satisfy topological order (Topological Order), acronym topology sequence. Briefly, to give a total order on the set of a partial order on a set, this operation is called Topological Sort.

From Baidu Encyclopedia

I understand: the formation of a legitimate access order directed acyclic graph all nodes have sort.

Make an analogy: to eat before worked as a waiter, worked as a waiter before cooking to - then these three things for topological order is cooking → → eat side dishes.

So specifically how to deal with it?
In fact there are two ways to achieve, but I personally being monolingual.
Use queue way, all the 0 degree point of the team, and then put a few points to delete contributions of other points of penetration, then put the 0 degree point of the team until the completion of the sort.
After the completion of topological sorting order can be used for dynamic topology planning.

The complete code is as follows:

#include<cstdio>
#include<queue>
using namespace std;
queue<int> que;
struct data
{
    int sta,to,nxt;
}e[500005],ine[500005],oute[500005];
int dfn[100005],tim,low[100005],stk[100005],cnt,cnti,cnto,head[100005],inhead[100005],outhead[100005]; 
bool vis[10005];
int tot,scc[100005],val[100005],a[100005],n,in[100005],order[100005],m,u,v,f[100005],ans;
void tarjan(int now)
{
    dfn[now]=++tim;//记录dfs序
    low[now]=tim;//当前能访问到dfs序最小的点就是自己
    stk[++cnt]=now;
    vis[now]=true;
    for (int i=head[now];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if (!dfn[to])
        {
            tarjan(to);
            low[now]=min(low[now],low[to]);
            //如果该点没被遍历过,那么就进行遍历。
        }
        else 
        {
            if (vis[to]) low[now]=min(low[now],dfn[to]);
            //必须判断是否在栈中。只有在同时在栈内的点才有可能构成强连通分量。
        }
    }
    if (low[now]==dfn[now])
    {
        tot++;//强连通分量的编号
        while (stk[cnt]!=now)
        {
            scc[stk[cnt]]=tot;
            val[tot]+=a[stk[cnt]];
            vis[stk[cnt]]=false;
            cnt--;
        }
        scc[stk[cnt]]=tot;
        val[tot]+=a[stk[cnt]];
        vis[stk[cnt]]=false;
        cnt--;
        //将栈中比u后进入的点和u本身出栈,这些点构成一个强联通分量,打上标记
    }
}
void topo()//拓扑排序
{
    cnt=0,cnti=0,cnto=0;
    for (int i=1;i<=n;i++)
    {
        for (int j=head[i];j;j=e[j].nxt)
        {
            if (scc[i]!=scc[e[j].to])
            {
                oute[++cnto].to=scc[e[j].to];
                oute[cnto].nxt=outhead[scc[i]];
                outhead[scc[i]]=cnto;
                in[scc[e[j].to]]++;
                ine[++cnti].sta=scc[i];
                ine[cnti].nxt=inhead[scc[e[j].to]];
                inhead[scc[e[j].to]]=cnti;
                //out前缀的变量是出边的记录
                //in前缀的变量是入边的记录,使用了一种另类的链式前向星
            }
        }
    }
    for (int i=1;i<=tot;i++)
        if (in[i]==0) que.push(i);//入度为零则入队
    cnt=0;
    while (!que.empty())
    {
        int u=que.front();
        que.pop();
        order[++cnt]=u;//记录顺序
        for (int i=outhead[u];i;i=oute[i].nxt)
        {
            int v=oute[i].to;
            in[v]--;
            if (in[v]==0) que.push(v);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=1;i<=m;i++) 
    {
        scanf("%d%d",&u,&v);
        e[i].to=v;
        e[i].nxt=head[u];
        head[u]=i;
        //链式前向星存原图
    }
    tim=0;
    for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
    //如果没有被遍历过的点要继续遍历。
    topo();
    for (int i=1;i<=tot;i++)
    {
        f[order[i]]=val[order[i]];
        for (int j=inhead[order[i]];j;j=ine[j].nxt)
            f[order[i]]=max(f[order[i]],f[ine[j].sta]+val[order[i]]);
        //很容易的一个动态规划
    }
    for (int i=1;i<=tot;i++) ans=max(f[i],ans);//统计答案
    printf("%d",ans);
    return 0;
}

Guess you like

Origin www.cnblogs.com/notscience/p/11822391.html