HDU 4612 边双连通+缩点

2 处理重边问题

HDU 4612

问题:

  • 无向图将边双联通分量缩点后添加一条边使得割边数量变得最少,最少是多少?

    思路:

  • 在2个距离最远的点添加一条边使得割边消失的最多,那么剩下的割边最少

  • dfs一次找到距离最远的2个点中的1个.(同时记录缩点后割边的总数),

  • 再一次dfs就能统计到另一个最远点的路径上的割边数量.

    技巧

  1. for (int j=head[i]; j!=-1; j=edge[j].next)遍历每个点的邻接表来建立缩点后无向图(vector存)

  2. e[i].vis来处理重边

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    #include <iostream>
    #include <vector>
    #include <cstring>
    #include <algorithm>

    using namespace std;
    const int maxn = 2e5+10;

    struct node {
    int to,next;
    bool vis;
    } edge[maxn*10];
    vector<int> e[maxn];
    int head[maxn],h[maxn],index1;
    int low[maxn],dfn[maxn],belong[maxn],stack_[maxn];
    int top,dps,cir,n,m;
    bool in_stack[maxn];

    void tarjan(int x) {
    in_stack[x] = 1;
    low[x] = dfn[x] = ++dps;
    stack_[top++] = x;
    for (int i=head[x]; i+1; i=edge[i].next) {
    int to = edge[i].to;
    if (edge[i].vis) continue;
    edge[i].vis = edge[i^1].vis = 1;
    if (!dfn[to]) {
    tarjan(to);
    low[x] = min(low[x],low[to]);
    } else if (in_stack[to])
    low[x] = min(low[x],dfn[to]);
    }
    int p;
    if (low[x] == dfn[x]) {
    cir++;
    do{
    p = stack_[--top];
    in_stack[p] = 0;
    belong[p] = cir;
    }while(p != x);
    }
    }

    bool vis[maxn];
    int point,max_edge,ans;
    void dfs(int x,int step) {
    vis[x] = 1;
    if (step > max_edge) max_edge=step,point = x;
    for (int i=0; i<e[x].size(); ++i) {
    int to = e[x][i];
    if (!vis[to]) {
    dfs(to,step+1);
    ans++;
    }
    }
    }

    void add(int x,int y) {
    edge[index1].vis = 0;
    edge[index1].to = y;
    edge[index1].next = head[x];
    head[x] = index1++;
    }

    void init() {
    index1 = 0;
    memset(head,-1,sizeof head);
    memset(in_stack,0,sizeof in_stack);
    memset(low,0,sizeof low);
    memset(dfn,0,sizeof dfn);
    dps = top = cir = 0;
    }
    int main() {
    freopen("1.in","r",stdin);
    while (scanf("%d%d",&n,&m) && (n+m)) {
    init();
    for (int i=1; i<=m; ++i) {
    int x,y;
    scanf("%d%d",&x,&y);
    add(x,y); add(y,x);
    }
    tarjan(1);
    for (int i=1; i<=n; ++i) e[i].clear();
    for (int i=1; i<=n; ++i)
    for (int j=head[i]; j!=-1; j=edge[j].next) {
    int to = edge[j].to;
    if (belong[to] != belong[i]) {
    e[belong[i]].push_back(belong[to]);
    }
    }
    memset(vis,0,sizeof vis);
    max_edge = ans = 0;
    dfs(1,0);
    int tempans = ans;
    memset(vis,0,sizeof vis);
    max_edge = 0;
    dfs(point,0);
    cout << tempans-max_edge << endl;
    }
    return 0;
    }

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!