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;
    }
    
  • 相关阅读:
    ASP.NET Web API 控制器执行过程(一)
    ASP.NET Web API 控制器创建过程(二)
    ASP.NET Web API 控制器创建过程(一)
    ASP.NET Web API WebHost宿主环境中管道、路由
    ASP.NET Web API Selfhost宿主环境中管道、路由
    ASP.NET Web API 管道模型
    ASP.NET Web API 路由对象介绍
    ASP.NET Web API 开篇示例介绍
    ASP.NET MVC 视图(五)
    ASP.NET MVC 视图(四)
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114276.html
Copyright © 2011-2022 走看看