ZOJ 3795 Grouping 强连通分量-tarjan

一开始我还天真的一遍DFS求出最长链以为就可以了

不过发现存在有向环,即强连通分量SCC,有向环里的每个点都是可比的,都要分别给个集合才行,最后应该把这些强连通分量缩成一个点,最后保证图里是 有向无环图才行,这个时候再找最长链,当然缩点之后的scc是有权值的,不能只看成1,缩点完了之后,用记忆化搜索DP就可以再On的复杂度内求出结果

所以现学了一下SCC-Tarjan,所谓Scc-tarjan,就是找到强连通分量并且缩点,特别好用,其原理就是利用dfs时间戳,每个点有自己的时间戳,同时再开一个记录通过孩子的路径能指向的最上边的节点的时间戳,lowlink,如果当前lowlink就等于自己,即找到了强连通分量,并且找到了最大的头头。所以一个点也是强连通分量

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
const int N = 100010;
stack<int> sta;
vector <int> G[N];
vector <int> G4[N];
int vis[N];
int n,m;
int pre[N],lowlink[N],sccno[N],w[N],dfs_clk,scc_cnt;
int dp[N];
void init()
{
    dfs_clk=scc_cnt=0;
    for (int i=0;i<=n;i++){
        G[i].clear();
        pre[i]=0;
        lowlink[i]=0;
        sccno[i]=0;
        vis[i]=0;
        w[i]=0;
        G4[i].clear();
    }
}
void dfs(int u)
{
    pre[u]=lowlink[u]=++dfs_clk;
    sta.push(u);
    for (int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if (!pre[v]){
            dfs(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        }
        else if (!sccno[v]){
            lowlink[u]=min(lowlink[u],pre[v]);
        }
    }
    if (lowlink[u]==pre[u]){
        scc_cnt++;
        for (;;){
            int x=sta.top();sta.pop();
            sccno[x]=scc_cnt;
            w[scc_cnt]++;
            if (x==u) break;
        }
    }
}
void tarjan()
{
    for (int i=1;i<=n;i++){
        if (!pre[i]) dfs(i);
    }
}
void calc(int u)
{
    if (dp[u]!=-1) return;
    dp[u]=w[u];
    int now=w[u];
    for (int j=0;j<G4[u].size();j++){
        int v=G4[u][j];
        calc(v);
        dp[u]=max(dp[u],dp[v]+now);
    }
}
void solve()
{
    for (int i=1;i<=n;i++){
        int u=sccno[i];
        for (int j=0;j<G[i].size();j++){
            int v=sccno[G[i][j]];
            if (u!=v) G4[u].push_back(v);
        }
    }
    for (int i=1;i<=scc_cnt;i++){
        dp[i]=-1;
    }
    for (int i=1;i<=scc_cnt;i++){
        calc(i);
    }
    int ans=0;
    for (int i=1;i<=scc_cnt;i++){
        ans=max(ans,dp[i]);
    }
    printf("%d\n",ans);
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        int a,b;
        while (m--)
        {
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
        }
        tarjan();
        solve();
    }
    return 0;
}

ZOJ 3795 Grouping 强连通分量-tarjan

时间: 2024-08-05 20:24:56

ZOJ 3795 Grouping 强连通分量-tarjan的相关文章

强连通分量(tarjan求强连通分量)

双DFS方法就是正dfs扫一遍,然后将边反向dfs扫一遍.<挑战程序设计>上有说明. 双dfs代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 6 using namespace std; 7 const int MAXN = 1e4 + 5; 8 vector <int> G[MAXN]; //图的邻接表

HDU 1269 强连通分量tarjan算法

迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6655    Accepted Submission(s): 2973 Problem Description 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房

图之强连通、强连通图、强连通分量 Tarjan算法

强连通分量 简介 在阅读下列内容之前,请务必了解图论基础部分. 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图. 这里想要介绍的是如何来求强连通分量. Tarjan 算法 Robert E. Tarjan (1948~) 美国人. Tarjan 发明了很多算法结构.光 Tarjan 算法就有很多,比如求各种联通分量的 Tarjan 算法,求 LCA(Lowest Comm

强连通分量tarjan

#include<iostream>//强连通分量tarjan #include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; #define maxn 400010 #define INF 1e18 int low[maxn],dfn[maxn],sta[maxn],d[maxn]/*value*/,dis[maxn]/*to

ZOJ 3795 Grouping(强联通分量 + 缩点 + Dp)

Problem Description: Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we need to divide all these N people into

【强连通分量&#183;Tarjan】bzoj1179: [Apio2009]Atm

新博的第一发! 因为这几天切了几道强连通分量,所以从这里begin [题目描述] Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定,在每个路口都设立了一个Siruseri 银行的ATM 取款机.令人奇怪的是,Siruseri的酒吧也都设在路口,虽然并不是每个路口都设有酒吧.Banditji 计划实施Siruseri 有史以来最惊天动地的ATM 抢劫.他将从市中心出发,沿着单向道路行驶,抢劫所有他途径的ATM 机,最终他将在一个酒吧庆祝他的胜利.使用高超的黑客技术,他获

求图的强连通分量--tarjan算法

一:tarjan算法详解 ?思想: ? ?做一遍DFS,用dfn[i]表示编号为i的节点在DFS过程中的访问序号(也可以叫做开始时间)用low[i]表示i节点DFS过程中i的下方节点所能到达的开始时间最早的节点的开始时间.(也就是之后的深搜所能到达的最小开始时间)初始时dfn[i]=low[i] ? ?在DFS过程中会形成一搜索树.在搜索树上越先遍历到的节点,显然dfn的值就越小. ? ?DFS过程中,碰到哪个节点,就将哪个节点入栈.栈中节点只有在其所属的强连通分量已经全部求出时,才会出栈. ?

ZOJ_3795 Grouping(强连通分量 拓扑)

题目请点我 题解: 这是我的第一道强连通分量,虽然参考了别人的代码,还是很有收获.强连通分量的查找和处理是很多图论题目的第一步,所以还是很重要,这道题只是有向图的强连通处理. 这道题因为题目有讲每组关系都是不小于,那么如果出现环的话那只有一种情况,就是环上所有人都是相等的年龄,则这个环上所有的人的比较关系都是可以等价的,这就是为什么我们要先对强连通分量尽行缩点处理,将每一个强连通分量作为一个整体,之后再依据层次关系构造拓扑序,利用拓扑序找到最长的一条序列. 算法讲解 代码参考 测试数据: 4 4

强连通分量tarjan缩点——POJ2186 Popular Cows

这里的Tarjan是基于DFS,用于求有向图的强联通分量. 运用了一个点dfn时间戳和low的关系巧妙地判断出一个强联通分量,从而实现一次DFS即可求出所有的强联通分量. §有向图中, u可达v不一定意味着v可达u.    相互可达则属于同一个强连通分量    (Strongly Connected Component, SCC) §有向图和它的转置的强连通分量相同 §所有SCC构成一个DAG(有向无环图) dfn[u]为节点u搜索的次序编号(时间戳),即首次访问u的时间 low[u]为u或u的