zoukankan      html  css  js  c++  java
  • HDU 4612 Warm up (边双连通分量+DP最长链)

    题意】给定一个无向图,问在允许加一条边的情况下,最少的桥的个数 【思路】对图做一遍Tarjan找出桥,把双连通分量缩成一个点,这样原图就成了一棵树,树的每条边都是桥。然后在树中求最长链,这样在两端点间连一条边就能形成环从而减少桥数。 不能更逗比。。多校第一场刚做出来的找最长链第二场就做错了= =,还一直以为是模板的问题。。。。。。  
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define MID(x,y) ((x+y)/2)
    #define mem(a,b) memset(a,b,sizeof(a))
    #pragma comment(linker,"/STACK:102400000,102400000")
    using namespace std;
    const int MAXV = 200005;
    const int MAXE = 2000005;
    struct node{
        int u, v;
        int next;
        bool bridge;
    }arc[MAXE];
    int cnt, head[MAXV];
    void init(){
        cnt = 0;
        mem(head, -1);
        return ;
    }
    void add(int u, int v){
        arc[cnt].u = u;
        arc[cnt].v = v;
        arc[cnt].next = head[u];
        arc[cnt].bridge = false;
        head[u] = cnt ++;
        arc[cnt].u = v;
        arc[cnt].v = u;
        arc[cnt].next = head[v];
        arc[cnt].bridge = false;
        head[v] = cnt ++;
        return ;
    }
    int id, dfn[MAXV], low[MAXV];
    int bridge_num;
    bool vis_arc[MAXE];              //一条边无向边(两个有向边)只访问一次,
    void tarjan(int u){
        dfn[u] = low[u] = ++ id;
        for (int i = head[u]; i != -1; i = arc[i].next){
            if (vis_arc[i]) continue;
            int v = arc[i].v;
            vis_arc[i] = vis_arc[i^1] = 1;
            if (!dfn[v]){
                tarjan(v);
                low[u] = min(low[u], low[v]);
                if (dfn[u] < low[v]){
                    arc[i].bridge = true;
                    arc[i^1].bridge = true;
                    bridge_num ++;
                }
            }
            else{
                low[u] = min(low[u], dfn[v]);
            }
        }
    }
    int bcc_num;
    bool vis[MAXV];
    int mark[MAXV];                  //标记点属于哪个边双连通分支
    vector  bcc[MAXV];
    
    void fill(int u){
        bcc[bcc_num].push_back(u);
        mark[u] = bcc_num;
        for (int i = head[u]; i != -1; i = arc[i].next){
            if (arc[i].bridge)  continue;
            int v = arc[i].v;
            if (mark[v] == 0)
                fill(v);
        }
    }
    void find_bcc(int n){
        mem(vis, 0);
        mem(mark, 0);
        //确定每个点所属边双联通分量
        for (int i = 1; i <= n; i ++){
            if (mark[i] == 0){
                ++ bcc_num;
                bcc[bcc_num].clear();
                fill(i);
            }
        }
        return ;
    }
    void solve(int n){
        id = bcc_num = bridge_num = 0;
        mem(dfn, 0);
        mem(low, 0);
        mem(vis_arc, 0);
        for (int i = 1; i <= n; i ++){
            if (!dfn[i])
                tarjan(i);
        }
        find_bcc(n);
        return ;
    }
    int maxlong;
    int dp[MAXV];
    void long_list(int bccu, int n){
        vis[bccu] = 1;
        int max1 =0,  max2 = 0;
        int num = 0;
        for (int p = 0; p < (int)bcc[bccu].size(); p ++){
            int u = bcc[bccu][p];
            for (int i = head[u]; i != -1; i = arc[i].next){
                if (arc[i].bridge){
                    int bccv = mark[arc[i].v];
                    if (!vis[bccv]){
                        num ++;
                        long_list(bccv, n);
                        if (dp[bccv] > max1){
                            max2 = max1;
                            max1 = dp[bccv];
                        }
                        else{
                            if (dp[bccv] > max2){
                                max2 = dp[bccv];
                            }
                        }
                    }
                }
            }
        }
        if (0 == num){
            dp[bccu] = 0;
        }
        else{
            if (num == 1)
                maxlong = max(maxlong, max1+1);
            else
                maxlong = max(maxlong, max1+max2+2);
            dp[bccu] = max1 + 1;
        }
        return ;
    }
    int n, m;
    int main(){
        while(scanf("%d %d", &n, &m) != EOF){
            if (n + m == 0)
                break;
            init();
            for (int i = 0; i < m; i ++){
                int u, v;
                scanf("%d %d", &u, &v);
                add(u, v);
            }
            solve(n);
            maxlong = 0;
            mem(dp, 0);
            mem(vis, 0);
            for (int i = 1; i <= bcc_num; i ++){
                if (!vis[i])
                    long_list(i, n);
            }
            printf("%d
    ", bridge_num - maxlong);
        }
        return 0;
    }
    
  • 相关阅读:
    导航栏下拉至一定高度后固定在顶部的特效
    laravel表单中文错误提示本地化
    laravel模板使用
    网站测试用例
    sublime安装ctags用于追踪函数
    ecshop头部添加所在城市
    php 常用的redis操作语法
    mysql where与 having的区别
    mysql 列类型以及属性特点
    不错的博客链接
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114276.html
Copyright © 2011-2022 走看看