zoukankan      html  css  js  c++  java
  • bzoj2730

    tarjan求割点

    我发现我还不会求割点

    首先我们发现如果整个图是一个点双,那么要放两个出口。答案是2 c(n, 2)

    如果不是,说明这个图存在割点能把图分成很多个部分,那么我们就要把割点求出来,每个点双和割点缩成一个点,这样就构成了一棵树。然后每个度数为一的点都要放一个出口,如果度数大于一就不用放,因为怎么割都和另一边的出口相连。

    求割点还是用tarjan,如果一个点的dfn<=low[son],说明儿子没有返祖边,那么这个点去掉肯定使儿子的那个连通块独立,所以这个点就是割点,标记一下,然后dfs染其他非割点的点,然后连边算度数算大小。

    奥妙重重的是low[u]=min(low[u],low[v])会错,这也告诉我们还是要按照标准来写。

    upd:因为可能v本身是个割点,如果翻上去就无法发现v是割点了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 510;
    int n, m, all, cnt, top, kase;
    int dfn[N], low[N], vis[N], belong[N], d[N], size[N];
    vector<int> G[N], g[N << 1];
    void tarjan(int u, int last)
    {
        dfn[u] = low[u] = ++all; 
        int child = 0;
        for(int i = 0; i < G[u].size(); ++i)
        {
            int v = G[u][i];
            if(!dfn[v]) 
            {
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
                ++child;
                if((u != 1 && low[v] >= dfn[u]) || (u == 1 && child > 1) && !belong[u])
                {    
                    vis[u] = 1;
                    belong[u] = ++cnt;
                    size[cnt] = 1;
                }
            }
            else if(v != last)
                low[u] = min(low[u], dfn[v]);
        }
    }
    void dfs(int u)
    {
        vis[u] = 1; 
        belong[u] = cnt;
        ++size[cnt];
        for(int i = 0; i < G[u].size(); ++i)
        {
            int v = G[u][i];
            if(!vis[v]) 
                dfs(v);
        }    
    }
    int main()
    {
    //    freopen("bzoj_2730.in", "r", stdin);
    //    freopen("bzoj_2730.out", "w", stdout);
        while(scanf("%d", &n))
        {
            if(!n) break;
            for(int i = 1; i <= n; ++i)
            {
                int u, v; scanf("%d%d", &u, &v);
                G[u].push_back(v);
                G[v].push_back(u);
                m = max(m, max(u, v));
            }
            tarjan(1, 0);
            for(int i = 1; i <= m; ++i) if(!vis[i])
            {
                ++cnt;
                dfs(i);
            }
            for(int i = 1; i <= m; ++i) 
                for(int j = 0; j < G[i].size(); ++j)
                {
                    int v = G[i][j];
                    if(belong[i] != belong[v])
                    {
                        g[belong[i]].push_back(belong[v]);
                        g[belong[v]].push_back(belong[i]);
                    }
                }
            if(cnt == 1)
            {
                printf("Case %d: 2 %lld
    ", ++kase, (ll)m * (ll)(m - 1ll) / 2ll);
                memset(size, 0, sizeof(size));
                memset(belong, 0, sizeof(belong));
                memset(dfn, 0, sizeof(dfn));
                memset(low, 0, sizeof(low));
                memset(vis, 0, sizeof(vis));
                memset(d, 0, sizeof(d));
                memset(belong, 0, sizeof(belong));
                for(int i = 1; i <= m; ++i)
                    G[i].clear();
                for(int i = 1; i <= cnt; ++i)
                    g[i].clear();
                cnt = 0;
                all = 0;
                m = 0;
                top = 0;        
                continue;
            }
            for(int i = 1; i <= cnt; ++i)
            {
                sort(g[i].begin(), g[i].end());
                g[i].erase(unique(g[i].begin(), g[i].end()), g[i].end());
                for(int j = 0; j < g[i].size(); ++j)
                {
                    ++d[i];
                    ++d[g[i][j]];
                }            
            }
            ll ans1 = 0, ans2 = 1;
            for(int i = 1; i <= cnt; ++i)
                if(d[i] == 2)
                {
                    ++ans1;
                    ans2 *= size[i];
                }
            printf("Case %d: %lld %lld
    ", ++kase, ans1, ans2);
            memset(size, 0, sizeof(size));
            memset(belong, 0, sizeof(belong));
            memset(dfn, 0, sizeof(dfn));
            memset(low, 0, sizeof(low));
            memset(vis, 0, sizeof(vis));
            memset(d, 0, sizeof(d));
            memset(belong, 0, sizeof(belong));
            for(int i = 1; i <= m; ++i)
                G[i].clear();
            for(int i = 1; i <= cnt; ++i)
                g[i].clear();
            cnt = 0;
            all = 0;
            m = 0;
            top = 0;
        }
    //    fclose(stdin); fclose(stdout);
        return 0;
    }
    View Code
  • 相关阅读:
    第七次会议记录
    第六次会议记录
    高老师有点可爱队 Alpha冲刺阶段博客目录
    开心括号(栈)
    Codeforces Round #696 (Div. 2)
    OLE和TLE的不同
    Educational Codeforces Round 102 (Rated for Div. 2)
    关于位运算新知
    牛客小白月赛31
    关于cin和getline读入字符串
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7074651.html
Copyright © 2011-2022 走看看