Redundant Paths——构造双连通图

题目链接

题意:

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

题解:

题意转换一下:

就是给了一个连通图,问加多少条边可以变成边双连通。

双连通图

我们将原图先缩点, 可以得到一棵树.然后我们统计叶子节点数目leaf(即度为1的点), 最小的加边数即(leaf+1)/2 (成对加边)

考虑重边

代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include<vector>
#include <map>
using namespace std;

const int maxn = 5010;//点数
const int maxm = 20010;//边数,因为是无向图,所以这个值要*2

struct Edge
{
    int to,next;
    bool cut;//是否是桥标记
} edge[maxm];
int head[maxn],tot;
int low[maxn],dfn[maxn],Stack[maxn],belong[maxn];//belong数组的值是1~scc
int Index,top;
int scc;//边双连通块数/强连通分量的个数
bool Instack[maxn];
int bridge;//桥的数目
int cut[maxn];
void addedge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    edge[tot].cut=false;
    head[u] = tot++;
}
void Tarjan(int u,int pre)
{
    int v;
    low[u] = dfn[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    int son=0;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(v == pre)continue;
        if( !dfn[v] )
        {
            son++;
            Tarjan(v,u);
            if( low[u] > low[v] )low[u] = low[v];
            if(low[v] > dfn[u])
            {
                bridge++;
                edge[i].cut = true;
                edge[i^1].cut = true;
            }
            if(u == pre && son > 1)cut[u] = true;
            if(u != pre && low[v] >= dfn[u])cut[u] = true;

        }
        else if( Instack[v] && low[u] > dfn[v] )
            low[u] = dfn[v];
    }

    if(low[u] == dfn[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            belong[v] = scc;
        }
        while( v!=u );
    }

}
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}
int du[maxn];
void solve(int n)
{
    memset(dfn,0,sizeof(dfn));
    memset(Instack,false,sizeof(Instack));
    memset(du,0,sizeof du);
    memset(cut,0,sizeof cut);
    Index = top = scc = 0;
    bridge = 0;
    for(int i = 1; i <= n; i++)
        if(!dfn[i])
            Tarjan(i,i);
    for(int i = 1; i <= n; i++)
        for(int j = head[i]; j != -1; j = edge[j].next)
            if(edge[j].cut)
                du[belong[i]]++;
    int ans=0;
    for(int i = 1; i <= scc; i++)
        if(du[i]==1)
            ans++;
    //找叶子结点的个数ans,构造边双连通图需要加边(ans+1)/2
    printf("%d\n",(ans+1)/2);

}
int main()
{
    int n,m;
    int u,v;
    while(scanf("%d%d",&n,&m)==2)
    {
        init();
        while(m--)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        solve(n);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/j666/p/11630735.html

时间: 2024-08-02 02:01:48

Redundant Paths——构造双连通图的相关文章

[POJ3177]Redundant Paths(双连通图,割边,桥,重边)

题目链接:http://poj.org/problem?id=3177 和上一题一样,只是有重边. 如何解决重边的问题? 1.  构造图G时把重边也考虑进来,然后在划分边双连通分量时先把桥删去,再划分,其中桥的一端的割点归入当前正在划分的边双连通分量.这个处理比较麻烦: 2.  在输入图G的边时,若出现重边,则不把重边放入图G,然后在划分边双连通分量时依然用Low划分. 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓

双连通分量+构造双连通图

构造双连通图:一个有桥的连通图,如何把它通过加边变成边双连通图? 一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥,然后删除这些桥边,剩下的每个连通块都是一个双连通子图.把每个双连通子图收缩为一个顶点,再把桥边加回来,最后的这个图一定是一棵树,边连通度为1. 统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf.则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2.具体方法为,首先把两个最近公共祖先最远的两个叶

poj3177 Redundant Paths 边双连通分量

#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define eps 1e-

【POJ 3177】Redundant Paths(双连通分量)

求出每个双连通分量缩点后的度,度为1的点即叶子节点.原图加上(leaf+1)/2条边即可变成双连通图. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <map> using namespace std; const int N = 5010; const int M = 10010; struct Edge { int

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

题目链接: poj3177 题意: 给出一张连通图,为了让任意两点都有两条通路(不能重边,可以重点),至少需要加多少条边 题解思路: 分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点. 缩点后,新图是一棵树,树的边就是原无向图桥. 现在问题转化为:在树中至少添加多少条边能使图变为双连通图. 结论:添加边数=(树中度为1的节点数+1)/2 具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上

POJ 3177 Redundant Paths(边双联通图)

Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forc

POJ 3177 Redundant Paths (双连通)

题目地址:POJ 3177 找出各个双连通分量度数为1的点,然后作为叶子节点,那么ans=(叶子结点数+1)/2.需要注意的是有重边. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include

LUOGU P2860 [USACO06JAN]冗余路径Redundant Paths (双联通,缩点)

传送门 解题思路 刚开始是找的桥,后来发现这样不对,因为一条链就可以被卡.后来想到应该缩点后找到度数为1 的点然后两两配对. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<set> using namespace std; const int MAXN = 5005; const int MAXM = 10005; inline i

POJ 3352 Road Construction 使得无向图边变双连通图

点击打开链接 Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8168   Accepted: 4106 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of