HDU 5409 双连通缩点

来源:互联网 发布:淘宝是日本人控股 编辑:程序博客网 时间:2024/05/16 20:29

HDU 5409

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5409

题意:

给一个图一些边,保证图连通

问对于每条边,如果去除该边后使得图中一些点不连通。设这些点(uv),要求使u尽量小,v尽量大,输出这样的(uv)。否则输出0 0

思路:

感谢http://www.cnblogs.com/oneshot/p/4748840.html

基本的思路就是找桥,然后桥两端找找对应的最大u和最小v

自己写的时候写完找桥就不会了,而且找桥找的特别菜~

有一个思路,即找出两边最大的u,设为u1u2。则u = minu1u2),v = u+1

证明:去掉桥以后,原图变成两个连通图。因为u越大越好所以取两个图中的最大 点,因为v必须大于u所以u只能取两个连通图中更小的u。设u1<u2。则在 第二个连通图中,一定能找到一个点u+1满足v最小。否则能用u+1来更新u1,使得u1更大。

因为对于每个桥割开的连通图内,只需要表现它最大点u的性质,所以可以强连通缩点, 最后再在缩成的“点”之间连桥。这样原图就变成一棵树,然后就变成树的遍历问题,

加个回溯就可以求出uv

 

缩点主要是给每个点设了个ID值,表示它属于哪一个新点。然后把需要的性质传给新 点就可以。

源码:

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#include <iostream>

#include <utility>

#include <string>

#include <vector>

using namespace std;

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

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

const int MAXN = 1e5 + 5;

typedef pair<int, int>pii;

vector<pii>lin[MAXN];

int n, m;

int bridge[MAXN];

int U[MAXN], V[MAXN];

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

int NewId[MAXN], vis[MAXN], IDs;

int maxu[MAXN], ans[MAXN];

void edge_init()

{

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

        lin[i].clear();

    int u, v;

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

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

        lin[u].push_back(make_pair(v, i));

        lin[v].push_back(make_pair(u, i));

        U[i] = u, V[i] = v;

    }

}

void DFS_bridge(int u, int fa)

{

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

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

        pii temp = lin[u][i];

        int v = temp.first, ID = temp.second;

        if(pre[v] == 0){

            DFS_bridge(v, u);

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

            if(low[v] > pre[u]) bridge[ID] = 1;

        }

        else if(pre[v] != 0 && v != fa)

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

    }

}

void DFS_shrink(int u, int fa)

{

    NewId[u] = IDs;

    vis[u] = 1;

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

        int v = lin[u][i].first;

        int ID = lin[u][i].second;

        if(!bridge[ID] && v != fa && vis[v] == 0){

            DFS_shrink(v, u);

        }

    }

}

void BCC_bridge()

{

    memset(bridge, 0, sizeof(bridge));

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

    clock = 0;

    DFS_bridge(1, -1);

}

void Shrink()

{

    memset(vis, 0, sizeof(vis));

    IDs = 0;

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

        if(vis[i] == 0){

            ++IDs;

            DFS_shrink(i, -1);

        }

    }

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

        lin[i].clear();

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

        if(bridge[i]){

            int u = NewId[U[i]], v = NewId[V[i]];

            lin[u].push_back(make_pair(v, i));

            lin[v].push_back(make_pair(u, i));

        }

    }

}

void DFS(int u, int fa)

{

    ans[u] = maxu[u];

    pre[u] = ++clock;

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

        int v = lin[u][i].first;

        if(v != fa && pre[v] == 0){

            DFS(v, u);

            ans[u] = gmax(ans[u], ans[v]);

        }

    }

}

int main()

{

    int t;

    scanf("%d", &t);

    while(t--){

        scanf("%d%d", &n, &m);

        edge_init();

        BCC_bridge();

        Shrink();

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

//            printf("U[%d] = %d, V[%d] = %d, bridge = %d\n", i, U[i], i, V[i], bridge[i]);

        memset(maxu, 0, sizeof(maxu));

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

            maxu[NewId[i]] = gmax(maxu[NewId[i]], i);

        int u;

        for(u = 1 ; u <= IDs ; u++)

            if(maxu[u] == n)

                break;

        clock = 0;

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

        DFS(u, -1);

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

            if(!bridge[i]){

                printf("0 0\n");

            }

            else{

                int u = NewId[U[i]], v = NewId[V[i]];

                if(pre[u] < pre[v])

                    swap(u, v);

                printf("%d %d\n", ans[u], ans[u] + 1);

            }

        }

    }

    return 0;

}

 

0 0
原创粉丝点击