poj 3177 Redundant Paths(边双连通分量+缩点)★

来源:互联网 发布:sql数据库实训总结 编辑:程序博客网 时间:2024/04/29 21:55

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

分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点。

缩点后,新图是一棵树,树的边就是原无向图的桥。

现在问题转化为:在树中至少添加多少条边能使图变为双连通图。

结论:添加边数=(树中度为1的节点数+1)/2

具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

其实求边双连通分量和求强连通分量差不多,每次访问点的时候将其入栈,当low[u]==dfn[u]时就说明找到了一个连通的块,则栈内的所有点都属于同一个边双连通分量,因为无向图要见反向边,所以在求边双连通分量的时候,遇到反向边跳过就行了。

#include <set>#include <map>#include <stack>#include <queue>#include <deque>#include <cmath>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define L(i) i<<1#define R(i) i<<1|1#define INF  0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-12#define maxn 300100#define MOD 1000000007const int N = 5000 + 5;const int M = 10000 + 5;struct EDGE{    int v,next;}edge[M*2];int head[N],low[N],dfn[N],belong[N],degree[N],sta[M],instack[M];int g,cnt,top,scc;int min(int a,int b){    return a < b ? a : b;}void AddEdge(int u,int v){    edge[g].v = v;    edge[g].next = head[u];    head[u] = g++;}void Tarjan(int u,int fa){    low[u] = dfn[u] = ++cnt;    sta[++top] = u;    instack[u] = 1;    for(int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].v;        if(i == (fa^1))            continue;        if(!dfn[v])        {            Tarjan(v,i);            low[u] = min(low[u],low[v]);        }        else if(instack[v])            low[u] = min(low[u],dfn[v]);    }    if(dfn[u] == low[u])    {        scc++;        while(1)        {            int v = sta[top--];            instack[v] = 0;            belong[v] = scc;            if(v == u)                break;        }    }}int main(){    int n,m,u,v;    scanf("%d%d",&n,&m);    g = cnt = top = scc = 0;    memset(head,-1,sizeof(head));    memset(low,0,sizeof(low));    memset(dfn,0,sizeof(dfn));    memset(instack,0,sizeof(instack));    memset(degree,0,sizeof(degree));    for(int i = 0; i < m; i++)    {        scanf("%d%d",&u,&v);        AddEdge(u,v);        AddEdge(v,u);    }    for(int i = 1; i <= n; i++)        if(!dfn[i])            Tarjan(1,-1);    for(int i = 1; i <= n; i++)    {        for(int j = head[i]; j != -1; j = edge[j].next)        {            v = edge[j].v;            if(belong[i] != belong[v])                degree[belong[i]]++;        }    }    int sum = 0;    for(int i = 1; i <= n; i++)        if(degree[i] == 1)            sum++;    int ans = (sum+1)/2;    printf("%d\n",ans);    return 0;}




0 0
原创粉丝点击