hiho 55 连通性·四

来源:互联网 发布:登录我的淘宝账号 编辑:程序博客网 时间:2024/06/05 14:13

问题

http://hihocoder.com/problemset/problem/1190?sid=787105
求点的连通分量

解法

使用tarjan,用堆栈记录边,在割点处弹栈,注意边可能有两次进入堆栈,我们记录边是否已经进入堆栈。

#include <bits/stdc++.h>using namespace std;enum{maxn = 20000+5, maxm = 100000+5};bool visitV[maxn];bool visitE[maxm];int eGroup[maxm];struct E{    int b;    int edgeId;};vector<E> G[maxn];int low[maxn];int dfn[maxn];int ess[maxm];int parent[maxn];int ret;int n, m;void dfs(int u){    static int essTop = -1;    static int count = 0;    visitV[u] = true;    dfn[u] = low[u] = ++count;    for (int i=0; i<G[u].size(); ++i)    {        int v = G[u][i].b;        int eid = G[u][i].edgeId;        if (visitE[eid]) // 只允许一次入栈            continue;        visitE[eid] = true;        ess[++essTop] = eid;        if (!visitV[v])        {            parent[v] = u;            dfs(v);            low[u] = min(low[u], low[v]);            if (low[v] >= dfn[u])// 找到割点,或者是根节点。弹栈            {                ++ret;                int j = essTop;                int minId = eid;                while(ess[j] != eid){                    minId = min(minId, ess[j--]);                }                while(j!= essTop)                {                    eGroup[ess[essTop--]] = minId;                }                --essTop;                eGroup[eid] = minId;            }        }else if (v != parent[u])        {            low[u] = min(low[u], dfn[v]);        }    }}int main(){    scanf("%d %d", &n, &m);    for (int i=1; i<=m; ++i)    {        int a, b;        scanf("%d %d", &a, &b);        G[a].push_back(E{b, i});        G[b].push_back(E{a, i});    }    memset(visitV, 0, sizeof(visitV));    memset(visitE, 0, sizeof(visitE));    parent[1] = 0;    ret =0;    dfs(1);    printf("%d\n", ret);    for (int i=1; i<= m;++i)        printf("%d ", eGroup[i]);    printf("\n");    return 0;}
0 0