hdu 4612 Warm up(缩点+树直径)

582 篇文章 0 订阅
19 篇文章 0 订阅

题目链接:hdu 4612 Warm up

解题思路

先双联通缩点,然后对缩完点的树求树的直径。

代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int maxn = 200005;
const int maxm = 1000005;

int N, M, E, first[maxn], jump[maxm<<1], linker[maxm<<1];
int dfsclock, L[maxm], R[maxm], iscut[maxm], pre[maxn];

int dfs (int u, int fa) {
    int lowu = pre[u] = ++dfsclock;
    for (int i = first[u]; i + 1; i = jump[i]) {
        int v = linker[i];
        if (!pre[v]) {
            int lowv = dfs(v, u);
            lowu = min(lowu, lowv);
            if (lowv > pre[u])
                iscut[i>>1] = 1;
        } else if (pre[v] < pre[u] && v != fa)
            lowu = min(lowu, pre[v]);
    }
    return lowu;
}

void dfs (int u, int fa, int be) {
    pre[u] = be;
    for (int i = first[u]; i + 1; i = jump[i]) {
        int v = linker[i];
        if (pre[v] || iscut[i>>1]) continue;
        dfs(v, u, be);
    }
}

void findEdge () {
    dfsclock = 0;
    memset(pre, 0, sizeof(pre));
    memset(iscut, 0, sizeof(iscut));
    for (int i = 1; i <= N; i++)
        if (!pre[i]) dfs(i, -1);

    dfsclock = 0;
    memset(pre, 0, sizeof(pre));
    for (int i = 1; i <= N; i++)
        if (!pre[i]) dfs(i, -1, ++dfsclock);
}

void addEdge(int u, int v) {
    jump[E] = first[u];
    linker[E] = v;
    first[u] = E++;
}

void init () {
    E = 0;
    memset(first, -1, sizeof(first));

    for (int i = 0; i < M; i++) {
        scanf("%d%d", &L[i], &R[i]);
        addEdge(L[i], R[i]);
        addEdge(R[i], L[i]);
    }
    findEdge();
}

const int inf = 0x3f3f3f3f;
int D[maxn];

int solve () {
    int n = dfsclock, u;

    queue<int> que;
    que.push(1);

    memset(D, inf, sizeof(D));
    D[1] = 0;
    while (!que.empty()) {
        u = que.front();
        que.pop();
        for (int i = first[u]; i + 1; i = jump[i]) {
            int v = linker[i];
            if (D[v] > D[u] + 1) {
                D[v] = D[u] + 1;
                que.push(v);
            }
        }
    }

    que.push(u);
    memset(D, inf, sizeof(D));
    D[u] = 0;
    while (!que.empty()) {
        u = que.front();
        que.pop();
        for (int i = first[u]; i + 1; i = jump[i]) {
            int v = linker[i];
            if (D[v] > D[u] + 1) {
                D[v] = D[u] + 1;
                que.push(v);
            }
        }
    }
    return n - D[u] - 1;
}

int main () {
    while (scanf("%d%d", &N, &M) == 2 && N + M) {
        init();

        E = 0;
        memset(first, -1, sizeof(first));
        for (int i = 0; i < M; i++) if (iscut[i]) {
            addEdge(pre[L[i]], pre[R[i]]);
            addEdge(pre[R[i]], pre[L[i]]);
        }
        printf("%d\n", solve());
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值