POJ3177

来源:互联网 发布:c语言node类型 编辑:程序博客网 时间:2024/06/06 13:07

Redundant Paths

题目链接

分类Graph

1.题意概述

  • n(1n5000)个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走。现已有m(n1m10000)条路,求至少要新建多少条路,使得任何两个牧场之间至少有两条独立的路。两条独立的路是指:没有公共边的路,但可以经过同一个中间顶点。

2.解题思路

  • 我们按边双连通分量缩点,新图成了一棵树,这个问题就转化为了:在树中至少添加多少条边能使得图变为双连通图?结论是cnt+12(其中cnt表示树中度数为1的点)!
  • 证明:具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是leaf+12次,把所有点收缩到了一起。

3.AC代码

#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <algorithm>#include <functional>#include <cmath>#include <vector>#include <queue>#include <deque>#include <stack>#include <map>#include <set>#include <ctime>using namespace std;#define N 5010/* head */struct Edge {    int to, next;    bool tag;} E[N << 2];int head[N], cnt;int dfn[N], low[N], degree[N], sec;int belong[N], block;int s[N], top;void init() {    memset(head, -1, sizeof head);    memset(dfn, 0, sizeof dfn);    memset(degree, 0, sizeof degree);    block = top = sec = cnt = 0;}void addedge(int u, int v) {    E[cnt].to = v;    E[cnt].next = head[u];    E[cnt].tag = 0;    head[u] = cnt++;}void tarjan(int u, int fa) {    dfn[u] = low[u] = ++sec;    s[top++] = u;    for (int i = head[u]; ~i; i = E[i].next) {        int v = E[i].to;        if (!dfn[v]) {            tarjan(v, u);            low[u] = min(low[u], low[v]);            if (dfn[u] < low[v]) {                E[i].tag = 1;                E[i ^ 1].tag = 1;            }        }        else if (v != fa) low[u] = min(low[u], dfn[v]);    }    if (low[u] == dfn[u]) {        int tmp;        block++;        do {            tmp = s[--top];            belong[tmp] = block;        } while (tmp != u);    }}int main() {    int n, m;    while (~scanf("%d%d", &n, &m)) {        init();        while (m--) {            int u, v;            scanf("%d%d", &u, &v);            addedge(u, v);            addedge(v, u);        }        tarjan(1, -1);        rep(u, 1, n + 1) {            for (int i = head[u]; ~i; i = E[i].next) {                if (E[i].tag == 1)                    degree[belong[u]]++;            }        }        int count = 0;        rep(i, 1, block + 1) {            if (degree[i] == 1)                count++;        }        printf("%d\n", (count + 1) / 2);    }    return 0;}