POJ 3177 Redundant Paths 边双连通分量+缩点

题目链接:

poj3177




题意:

给出一张连通图,为了让任意两点都有两条通路(不能重边,可以重点),至少需要加多少条边




题解思路:

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

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

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

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

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


代码:

#include
#include
#include
#define maxn 5050
using namespace std;
struct node
{
    int to,tag,next;
} edge[maxn*4];
int head[maxn];
int s;

int dfn[maxn],low[maxn],num;

int stack[maxn],top;

int belong[maxn],block;   //连通块

void init()
{
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    block=num=top=s=0;
}

void addedge(int a,int b)
{
    edge[s]= {b,0,head[a]};
    head[a]=s++;
}

void Tarjan(int u,int pre)
{
    dfn[u]=low[u]=++num;
    stack[top++]=u;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(dfn[u]



你可能感兴趣的:(算法)