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;
}
原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114276.html