• UVALive 5135 Mining Your Own Business 双连通分量


    据说这是一道Word Final的题,Orz。。。

    原题链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3136

    题意:

    给你一个联通图,让你选择一些点,使得这个图的任意一个点消失后,其余的点都能到达某个你选择的点。问你最少选择哪些点,并且输出在最优的情况下,有多少方案。

    题解:

    一眼看过去,做法很简单,就删掉所有的割点后,考察联通块的个数就好。但这道题满满的坑。。要不怎么是总决赛的题。。

    首先如果这个图只有一个联通块,那么答案就应该是任选两个点,这是因为,如果其中一个点挂了,还能走另外一个点。

    如果一个联通块有大于一个割点,那么这个联通块就不需要,这是因为两个割点不可能同时挂了。

    代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<set>
    #define MAX_V 50004
    using namespace std;
    
    int V=0;
    vector<int> G[MAX_V];
    int N;
    
    int dfn[MAX_V],low[MAX_V],ind=0;
    bool vis[MAX_V];
    bool isCut[MAX_V];
    int tot=0;
    
    long long ways=1;
    long long tmp=0;
    long long cnt=0;
    
    bool used[MAX_V];
    set<int> se;
    
    void init(){
        se.clear();
        V=ind=cnt=tmp=0;
        ways=1;
        memset(used,0,sizeof(used));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(vis,0,sizeof(vis));
        memset(isCut,0,sizeof(isCut));
        for(int i=0;i<=N+2;i++)G[i].clear();
    }
    
    void Tarjan(int u,int p) {
        dfn[u] = low[u] = ++ind;
        vis[u]=1;
        int child = 0;
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if (v == p)continue;
            if (!vis[v]) {
                child++;
                Tarjan(v, u);
                low[u] = min(low[v], low[u]);
                if (p == 0 && child > 1)isCut[u] = 1;
                if (p&&low[v] >= dfn[u])
                    isCut[u] = 1;
                tot+=isCut[u];
            }
            else
                low[u] = min(dfn[v], low[u]);
        }
    }
    
    void dfs(int u) {
        if (used[u] || isCut[u])return;
        tmp++;
        used[u] = 1;
        for (int i = 0; i < G[u].size(); i++){
            int v=G[u][i];
            if(isCut[v]){
                se.insert(v);
                continue;
            }
            dfs(v);
        }
    }
    
    int main() {
        int cas = 0;
        cin.sync_with_stdio(false);
        while (cin >> N) {
            tot=0;
            if (N == 0)break;
            init();
            for (int i = 0; i < N; i++) {
                int u, v;
                cin >> u >> v;
                V = max(V, max(u, v));
                G[u].push_back(v);
                G[v].push_back(u);
            }
            Tarjan(1, 0);
            cout << "Case " << ++cas << ": ";
            if (tot == 0) {
                cout << 2 << " " << (long long)V * (V - 1) / 2 << endl;
                continue;
            }
            for (int u = 1; u <= V; u++) {
                if (isCut[u])continue;
                tmp = 0;
                if (!used[u]) {
                    se.clear();
                    dfs(u);
                    if (se.size() == 1 && tmp) {
                        ways *= tmp;
                        cnt++;
                    }
                }
            }
            cout << cnt << " " << ways << endl;
        }
        return 0;
    }

     

  • 相关阅读:
    Python函数篇(7)-正则表达式
    Python函数篇(6)-常用模块及简单的案列
    Python函数篇(5)-装饰器及实例讲解
    Android 涂鸦最佳实践
    事件总线框架---Otto
    Android App补丁更新
    Android实现换肤功能(二)
    Android实现换肤功能(一)
    网络请求框架---Volley
    注解框架---AndroidAnnotations
  • 原文地址:https://www.cnblogs.com/HarryGuo2012/p/4791057.html
Copyright © 2020-2023  润新知