hiho 55 連通性·四

問題

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;
}
發佈了107 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章