HDU 3844 双连通分量

HDU 3844

题目链接:

题意:

给一个图,保证连通。问至少修几个通往地上的通道,使得其中一个点坏掉的时候,其他点都有通道可以通向地面。

思路:

上来先想到应该是划分双连通分量,双连通分量缩点。

这是错的啊,这是错的啊,这是错的啊!只有边双连通分量才能缩点啊!

改成点双连通分量就行,然后再注意些小问题最后答案注意乘法不爆long long,比如n要清0

源码:

邻接表版

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#include <iostream>

#include <vector>

#include <stack>

#include <utility>

using namespace std;

typedef pair<int,int> pii;

#define LL long long

#define gmax(a,b) ((a) > (b) ? (a) : (b))

#define gmin(a,b) ((a) < (b) ? (a) : (b))

#define MAXN (200005)

vector<int>lin[MAXN], bcc[MAXN];

stack<pii>sta;

int up;

int n, m;

int pre[MAXN], low[MAXN], clock;

int bccno[MAXN], bcccnt;

int iscut[MAXN];

int first[MAXN];

LL cnt, ans;

 

void DFS_iscut(int u, int fa)

{

    pre[u] = low[u] = ++clock;

    int child = 0;

    for(int i = 0 ; i < (int)lin[u].size() ; i++){

        int v = lin[u][i];

        if(pre[v] == 0){

            sta.push(make_pair(u, v));

            child++;

            DFS_iscut(v, u);

            low[u] = gmin(low[u], low[v]);

            if(low[v] >= pre[u]){

                iscut[u] = 1;

                bcccnt++;

                bcc[bcccnt].clear();

                while(!sta.empty()){

                    pii p = sta.top();  sta.pop();

                    if(bccno[p.first] != bcccnt){

                        bccno[p.first] = bcccnt;

                        bcc[bcccnt].push_back(p.first);

                    }

                    if(bccno[p.second] != bcccnt){

                        bccno[p.second] = bcccnt;

                        bcc[bcccnt].push_back(p.second);

                    }

                    if(p.first == u && p.second == v)

                        break;

                }

            }

        }

        else if(v != fa){

            if(pre[u] > pre[v]){

                sta.push(make_pair(u, v));

                low[u] = gmin(low[u], pre[v]);

            }

        }

    }

    if(fa < 0 && child <= 1)

        iscut[u] = 0;

}

int main()

{

    int cas = 0;

    while(scanf("%d", &m) != EOF && m){

        for(int i = 1 ; i <= m + 1 ; i++)

            lin[i].clear();

        int u, v;

        n = 0;

        memset(first, 0, sizeof(first));

        for(int i = 1 ; i <= m ; i++){

            scanf("%d%d", &u, &v);

            n = gmax(n, u), n = gmax(n, v);

            if(first[u] == 0)   first[u] = 1, lin[u].clear();

            lin[u].push_back(v);

            if(first[v] == 0)   first[v] = 1, lin[v].clear();

            lin[v].push_back(u);

        }

        cnt = 0, ans = 1;

        memset(pre, 0, sizeof(pre));

        memset(bccno, 0, sizeof(bccno));

        memset(iscut, 0, sizeof(iscut));

        bcccnt = 0;

        clock = 0;

        while(!sta.empty()) sta.pop();

        for(int i = 1 ; i <= n ; i++)

            if(pre[i] == 0) DFS_iscut(i, -1);

        if(bcccnt == 1){

            cnt = 2;

            LL z = n;

            ans = z * (z - 1) / 2;

        }

        else{

            cnt = 0;

            ans = 1;

//            printf("bcccnt = %d\n", bcccnt);

            for(int i = 1 ; i <= bcccnt ; i++){

                int tmark = 0;

//                printf("i = %d bcc = ", i);

                LL z = (int)bcc[i].size();

                for(int j = 0 ; j < (int)bcc[i].size() ; j++){

//                    printf("%d ", bcc[i][j]);

                    if(iscut[bcc[i][j]])    tmark++;

                }

//                printf("\n");

//                printf("tmark = %d\n", tmark);

//                printf("\n");

                if(tmark == 1){

                    cnt++;

                    ans *= (z - 1);

                }

            }

        }

        printf("Case %d: %I64d %I64d\n", ++cas, cnt, ans);

    }

    return 0;

}

 

前向星版(差不多好嘛)

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#include <iostream>

#include <vector>

#include <stack>

#include <utility>

using namespace std;

typedef pair<int,int> pii;

#define LL long long

#define gmax(a,b) ((a) > (b) ? (a) : (b))

#define gmin(a,b) ((a) < (b) ? (a) : (b))

#define MAXN (100005)

vector<int>lin[MAXN], bcc[MAXN];

stack<pii>sta;

int up;

int n, m;

int pre[MAXN], low[MAXN], clock;

int bccno[MAXN], bcccnt;

int iscut[MAXN];

int head[MAXN];

struct Edge

{

    int u, v, ne;

    Edge(){}

    Edge(int _u, int _v){u = _u, v = _v, ne = head[u];}

}edge[MAXN * 2];

int edge_cnt;

void addedge(int u, int v)

{

    edge[edge_cnt] = Edge(u, v);

    head[u] = edge_cnt++;

}

void DFS_iscut(int u, int fa)

{

    pre[u] = low[u] = ++clock;

    int child = 0;

    for(int i = head[u] ; i != -1 ; i = edge[i].ne){

        int v = edge[i].v;

        if(pre[v] == 0){

            sta.push(make_pair(u, v));

            child++;

            DFS_iscut(v, u);

            low[u] = gmin(low[u], low[v]);

            if(low[v] >= pre[u]){

                iscut[u] = 1;

                bcccnt++;

                bcc[bcccnt].clear();

                while(!sta.empty()){

                    pii p = sta.top();  sta.pop();

                    if(bccno[p.first] != bcccnt){

                        bccno[p.first] = bcccnt;

                        bcc[bcccnt].push_back(p.first);

                    }

                    if(bccno[p.second] != bcccnt){

                        bccno[p.second] = bcccnt;

                        bcc[bcccnt].push_back(p.second);

                    }

                    if(p.first == u && p.second == v)

                        break;

                }

            }

        }

        else if(v != fa){

            if(pre[u] > pre[v]){

                sta.push(make_pair(u, v));

                low[u] = gmin(low[u], pre[v]);

            }

        }

    }

    if(fa < 0 && child <= 1)

        iscut[u] = 0;

}

int main()

{

//    freopen("data.txt", "r", stdin);

//    freopen("data2.txt", "w", stdout);

    int cas = 0;

    while(scanf("%d", &m) != EOF && m){

        for(int i = 1 ; i <= m + 1 ; i++)

            lin[i].clear();

        int u, v;

        edge_cnt = 0;

        n = 0;

        memset(head, -1, sizeof(head));

        for(int i = 1 ; i <= m ; i++){

            scanf("%d%d", &u, &v);

            n = gmax(n, u), n = gmax(n, v);

//            if(first[u] == 0)   first[u] = 1, lin[u].clear();

//            lin[u].push_back(v);

//            if(first[v] == 0)   first[v] = 1, lin[v].clear();

//            lin[v].push_back(u);

            addedge(u, v);

            addedge(v, u);

        }

        int cnt = 0;

        LL ans = 1;

        memset(pre, 0, sizeof(pre));

        memset(bccno, 0, sizeof(bccno));

        memset(iscut, 0, sizeof(iscut));

        bcccnt = 0;

        clock = 0;

        while(!sta.empty()) sta.pop();

        for(int i = 1 ; i <= n ; i++)

            if(pre[i] == 0) DFS_iscut(i, -1);

//        for(int i = 1 ; i <= bcccnt ; i ++){

//            printf("bcccnt = %d\n", i);

//            for(int j = 0 ; j < (int)bcc[i].size() ; j++)

//                printf("%d ", bcc[i][j]);

//            printf("\n");

//        }

//        printf("bcc\n");

        if(bcccnt == 1){

            cnt = 2;

            LL z = n;

            ans = z * (z - 1) / 2;

        }

        else{

            for(int i = 1 ; i <= bcccnt ; i++){

                int tmark = 0;

                LL z = (int)bcc[i].size();

                for(int j = 0 ; j < (int)bcc[i].size() ; j++){

                    if(iscut[bcc[i][j]])    tmark++;

                }

                if(tmark == 1){

                    cnt++;

                    ans *= (z - 1);

                }

            }

        }

        printf("Case %d: %d %I64d\n", ++cas, cnt, ans);

    }

    return 0;

}

 

你可能感兴趣的:(HDU 3844 双连通分量)