hdu4612-Warm up(边的双连通分量)

题意:有n个点,m条边,有重边。现在可以任意在图上添加一条边,求桥的最少数目。

题解:思路就是求出双连通分量之后缩点成为一棵树,然后求出树的直径,连接树的直径就能减少最多的桥。

难点在于:有!重!边!

像我这样习惯于无脑用模板的人来说。。。。头疼死了。。。。。。

既然有重边,dfs的时候就不要标记点,以边为标记,然后照常求分量就好了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define pk(x) printf("x=%d\n", x)
using namespace std;
#define PI acos(-1.0)
#define EPS 1E-6
#define clr(x,c) memset(x,c,sizeof(x))
typedef long long ll;
typedef pair<int, int> PII;

const int N = 200005;
const int M = 2000005;

struct Edge {
    int from, to, next;
    int cut;
} edge[M];
int cnt_edge;
int head[N];
void add_edge(int u, int v)
{
    edge[cnt_edge].from = u;
    edge[cnt_edge].to = v;
    edge[cnt_edge].next = head[u];
    edge[cnt_edge].cut = 0;
    head[u] = cnt_edge++;
}

int dfn[N]; int idx;
int low[N];
int stk[N]; int top;
int kind[N]; int cnt;
bool in[N];

void tarjan(int u, int pre)
{
    low[u] = dfn[u] = ++idx;
    in[u] = true;
    stk[++top] = u;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (i == pre) continue;
        if (!dfn[v])
        {
            tarjan(v, i^1);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u])
            {
                edge[i].cut = true;
                edge[i ^ 1].cut = true;
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u])
    {
        cnt++;
        int v;
        do {
            v = stk[top--];
            in[v] = false;
            kind[v] = cnt;
        } while (u != v);
    }
}

vector<int> G[N];
int ans, ansv;

void dfs(int u, int fa, int d) {
    if (ans < d) {
        ans = d;
        ansv = u;
    }
    for (unsigned i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if (v == fa) continue;
        dfs(v, u, d+1);
    }
}

void init()
{
    for (int i = 0; i < N; ++i) G[i].clear();
    memset(dfn, 0, sizeof dfn);
    memset(head, -1, sizeof head);
    top = idx = cnt = cnt_edge = 0;
}
int main()
{
    int n, m;
    while (~scanf("%d%d", &n, &m)) {
        if (n + m == 0) break;
        init();
        int u, v;
        for (int i = 0; i < m; ++i) {
            scanf("%d%d", &u, &v);
            add_edge(u, v);
            add_edge(v, u);
        }
        tarjan(1, -1);

        int ret = 0;
        for (int i = 0; i < cnt_edge; ++i) {
            if (edge[i].cut) {
                int u = edge[i].from;
                int v = edge[i].to; if (u < v)
                ret++;
                G[ kind[u] ].push_back( kind[v] );
            }
        }
        ans = 0; ansv = 0; dfs(1, -1, 0);
        ans = 0; dfs(ansv, -1, 0);
        printf("%d\n", ret-ans);

    }
    return 0;
}
/**
6 6
1 2 2 3 3 4 4 5 2 6 6 2

6 8
1 2 2 3 3 4 4 5 2 6 6 2 1 3 4 7

5 4
2 1 2 3 2 4 2 5

5 5
2 1 2 3 2 4 2 5 3 4

5 5
1 2 2 3 3 4 3 4 4 5


0
1
2
0
0
*/

 

======

wa:12次,tle:1次,mle:3次,ce:2次

一颗赛艇。。。

posted @ 2016-09-18 20:39  我不吃饼干呀  阅读(277)  评论(0编辑  收藏  举报