zoukankan      html  css  js  c++  java
  • CodeForces

    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 ("
    ") ;
        }
    }
    
    //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;
    }
    
  • 相关阅读:
    2. Add Two Numbers
    1. Two Sum
    22. Generate Parentheses (backTracking)
    21. Merge Two Sorted Lists
    20. Valid Parentheses (Stack)
    19. Remove Nth Node From End of List
    18. 4Sum (通用算法 nSum)
    17. Letter Combinations of a Phone Number (backtracking)
    LeetCode SQL: Combine Two Tables
    LeetCode SQL:Employees Earning More Than Their Managers
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/14313617.html
Copyright © 2011-2022 走看看