Bridges Gym - 100712H  无向图的边双连通分量,Tarjan缩点

http://codeforces.com/gym/100712/attachments

题意是给定一个无向图,要求添加一条边,使得最后剩下的桥的数量最小。

注意到在环中加边是无意义的。

那么先把环都缩成一个点,然后重新建立一颗树,找出树的直径就好。

 

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 1e5 + 20;
struct Edge {
    int u, v, tonext;
}e[maxn * 2], tree[maxn * 2];
int first[maxn], num;
int first_tree[maxn], num_tree;
void addEdge(int u, int v) {
    ++num;
    e[num].u = u, e[num].v = v, e[num].tonext = first[u];
    first[u] = num;
}
int DFN[maxn], low[maxn], when, st[maxn], top;
int id[maxn], toSelid;
bool vis[maxn];
void tarjan(int cur, int fa) {
    DFN[cur] = low[cur] = ++when;  //时间戳
    st[++top] = cur; //进栈
    vis[cur] = true;
    for (int i = first[cur]; i; i = e[i].tonext) {
        int v = e[i].v;
        if (v == fa) continue;
        if (!DFN[v]) { //没访问过
            tarjan(v, cur);
            low[cur] = min(low[cur], low[v]);
        } else if (vis[v]) { // 访问过,而且还在栈里
            low[cur] = min(low[cur], DFN[v]);
        }
    }
    if (low[cur] == DFN[cur]) { //这个是强连通分量的根节点。
        ++toSelid;
        do {
            id[st[top]] = toSelid;      //块id
//            sum[toSelId]++;        //id节点个数
//            printf("%d ", st[top]);
            vis[st[top]] = false;
            top--;
        } while (cur != st[top + 1]);
//        printf("\n");
    }
}

void solveTarjan(int n) {
    memset(DFN, 0, sizeof DFN);
    memset(low, 0, sizeof low);
    memset(vis, 0, sizeof vis);
    when = top = toSelid = 0;
    for (int i = 1; i <= n; ++i) {
        if (!DFN[i]) tarjan(i, i);
    }
}
void addEdgeTree(int u, int v) {
    ++num_tree;
    tree[num_tree].u = u, tree[num_tree].v = v, tree[num_tree].tonext = first_tree[u];
    first_tree[u] = num_tree;
}

struct bfsnode {
    int cur, cnt;
    bfsnode(int _cur, int _cnt) {
        cur = _cur;
        cnt = _cnt;
    }
};
int tree_diameter(int begin, bool flag) {
    memset(vis, 0, sizeof vis);
    queue<struct bfsnode> que;
    while (!que.empty()) que.pop();
    que.push(bfsnode(begin, 0));
    vis[begin] = true;
    int to = begin, mx = 0;
    while (!que.empty()) {
        struct bfsnode t = que.front();
        que.pop();
        for (int i = first_tree[t.cur]; i; i = tree[i].tonext) {
            int v = tree[i].v;
            if (vis[v]) continue;
            vis[v] = true;
            que.push(bfsnode(v, t.cnt + 1));
            if (mx < t.cnt + 1) {
                to = v;
                mx = t.cnt + 1;
            }
        }
    }
    if (flag) return mx;
    else return to;
}


void work() {
    memset(first, 0, sizeof first);
    memset(first_tree, 0, sizeof first_tree);
    num = num_tree = 0;
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        addEdge(u, v);
        addEdge(v, u);
    }
    solveTarjan(n);
//    for (int i = 1; i <= n; ++i) {
//        cout << id[i] << " ";
//    }
    for (int i = 1; i <= n; ++i) {
        for (int j = first[i]; j; j = e[j].tonext) {
            int v = e[j].v;
            if (id[i] == id[v]) continue;
            addEdgeTree(id[i], id[v]);
            addEdgeTree(id[v], id[i]);
        }
    }
    int res = tree_diameter(1, 0);
    int di = tree_diameter(res, 1);
    int ans = toSelid - di - 1;
    ans = max(ans, 0);
    cout << ans << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    int t;
    scanf("%d", &t);
    while (t--) work();
    return 0;
}
View Code

 

posted on 2017-03-31 19:08  stupid_one  阅读(284)  评论(0编辑  收藏  举报

导航