CodeForces - 1000E We Need More Bosses(tarjan缩点、树上直径)

CF1000E We Need More Bosses

题目大意:

n点m边无向图,找到两个点s、t,使得s到t必须经过的边最多,求最多的必须经过边数。

思路:

题目关键在于对“必须经过的边”的理解,拿样例1来说

5 5					5
1 2					|
2 3					2
3 1				       / \
4 1				      3---1
5 2					  |
					  4

在同一个双连通分量中,任意两点都至少有两条简单路径,所以一个双连通分量内的点都不是必须经过的边,自然想到使用tarjan缩点,缩点后得到的无向图无环而形成了一棵树,我们使用两次dfs求得树上直径即可得到答案。

Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 300010;
// const int N = 10;

int dfn[N], low[N], co[N]/*缩点后每个点对应的标号*/, col/*缩点后还有几个点*/, num/*时间戳*/;
int st[N], top;
bool vis[N];

vector<int> G[N << 1], G2[N << 1];
int n, m;
int maxdis, maxv;

int min(int a, int b) { return a < b ? a : b; }

void tarjan(int x, int fa) {
    dfn[x] = low[x] = ++num;
    st[++top] = x;
    vis[x] = 1;
    for (int i = 0; i < G[x].size(); i++) {
        int v = G[x][i];
        if (v == fa) continue;
        if (!dfn[v]) { //没访问过
            tarjan(v, x);
            low[x] = min(low[x], low[v]);
        } else if (vis[v]) { //在栈中
            low[x] = min(low[x], dfn[v]);
        }
    }
    if (low[x] == dfn[x]) { //防止一个环遍历到一半就出栈了
        col++;
        while (1) {
            co[st[top]] = col;
            // printf("%d ", st[top]);
            vis[st[top]] = 0;
            if (st[top--] == x) break;
        }
        //printf ("\n") ;
    }
}

//u:dfs的源点,f: u点的父节点,d2s:u点到源点的距离
void dfs(int u, int f, int d2s) {
	if (maxdis < d2s){
		maxdis = d2s;
		maxv = u;
	}
        for (int i = 0; i < G2[u].size(); i++) {
            int v = G2[u][i];
            if (v == f) continue;
            dfs(v, u ,d2s + 1);
        }
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int u, v; cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    tarjan(1, 0);
    for (int i = 1; i <= n; i++) { //缩点后遍历原图重新建图为G2
        for (int j = 0; j < G[i].size(); j++) {
            int v = G[i][j];
            if (co[i] != co[v]) { //省去同一个环内的点的连边
                G2[co[i]].push_back(co[v]);
            }
        }
    }
    //在缩点后的树上求最长距离
    dfs(1, -1, 0);
    maxdis = 0;
    dfs(maxv, -1, 0);
    cout << maxdis << endl;
    return 0;
}
posted @ 2021-01-22 15:32  Nepenthe8  阅读(135)  评论(0编辑  收藏  举报