HDU 4612 Warm up(边双联通求树的直径)

Problem Description

  N planets are connected by M bidirectional channels that allow instant transportation. It‘s always possible to travel between any two planets through these channels.

  If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.

People don‘t like to be isolated. So they ask what‘s the minimal number of bridges they can have if they decide to build a new channel.

  Note that there could be more than one channel between two planets.

Input

  The input contains multiple cases.

  Each case starts with two positive integers N and M , indicating the number of planets and the number of channels.

  (2<=N<=200000, 1<=M<=1000000)

  Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N.

  A line with two integers ‘0‘ terminates the input.

Output

  For each case, output the minimal number of bridges after building a new channel in a line.

Sample Input

4 4
1 2
1 3
1 4
2 3
0 0 

Sample Output

0

Source

2013 Multi-University Training Contest 2

题意:加入一条边后的最小桥数。

边双联通缩点求树的直径,将直径两端连接就是减少的最多桥数。

重边问题:注意重边。又有就是要扩栈!!

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<bitset>
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
typedef long long LL;
typedef pair<int,int>pil;
const int maxn=200000+100;
const int maxm=3000000+100;
struct node{
    int to,next;
    bool col;//为桥
}e[maxm],e1[maxm];
int head[maxn],cnt,cntE,cnte;
int DFN[maxn],low[maxn];
int s[maxn],instack[maxn];
int idex,top,bridge;
int belong[maxn],h[maxn];
int d[maxn],vis[maxn];//为割;删除点后增加的联通快
int n,m;
void init()
{
    cnt=top=idex=0;
    cnte=bridge=cntE=0;
    CLEAR(head,-1);
    CLEAR(DFN,0);
    CLEAR(low,0);
    CLEAR(instack,0);
    CLEAR(belong,0);
    CLEAR(h,-1);
    CLEAR(vis,0);
    CLEAR(d,0);
}
void addedge(int u,int v)
{
    e[cntE].to=v;e[cntE].next=head[u];
    e[cntE].col=false;head[u]=cntE++;
}
void addedge1(int u,int v)
{
    e1[cnte].to=v;e1[cnte].next=h[u];
    h[u]=cnte++;
}
void Tarjan(int u,int pre)
{
    int v;
    low[u]=DFN[u]=++idex;
    s[top++]=u;
    instack[u]=1;
    int pre_num=0;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        v=e[i].to;
        if(v==pre&&!pre_num)
        {
            pre_num++;
            continue;
        }
        if(!DFN[v])
        {
            Tarjan(v,u);
            if(low[u]>low[v]) low[u]=low[v];
            if(low[v]>DFN[u])//桥
            {
                bridge++;
                e[i].col=true;
                e[i^1].col=true;
            }
        }
        else if(instack[v]&&low[u]>DFN[v])
            low[u]=DFN[v];
    }
    if(low[u]==DFN[u])
    {
        cnt++;
        do{
            v=s[--top];
            instack[v]=0;
            belong[v]=cnt;
        }while(v!=u);
    }
}
void dfs(int u,int depth)
{
    d[u]=depth;
    vis[u]=1;
    for(int i=h[u];i!=-1;i=e1[i].next)
    {
        int v=e1[i].to;
        if(!vis[v])
            dfs(v,depth+1);
    }
}
void work()
{
    REPF(i,1,n)
       if(!DFN[i])  Tarjan(i,-1);
    REPF(u,1,n)
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            if(belong[u]!=belong[v])
            {
                addedge1(belong[u],belong[v]);
                addedge1(belong[v],belong[u]);
            }
        }
    dfs(1,0);
    int pos=1;
    for(int i=1;i<=cnt;i++)
        if(d[i]>d[pos])  pos=i;
    CLEAR(vis,0);
    CLEAR(d,0);
    dfs(pos,0);
    int ans=0;
    REPF(i,1,cnt)  ans=max(ans,d[i]);
    printf("%d\n",bridge-ans);
}
int main()
{
    int u,v;
    while(~scanf("%d%d",&n,&m)&&(n+m))
    {
        init();
        REPF(i,1,m)
        {
            scanf("%d%d",&u,&v);
            if(u==v)  continue;
            addedge(u,v);
            addedge(v,u);
        }
        work();
    }
    return 0;
}
时间: 2024-10-12 04:07:42

HDU 4612 Warm up(边双联通求树的直径)的相关文章

HDU 4612 Warm up —— (缩点 + 求树的直径)

题意:一个无向图,问建立一条新边以后桥的最小数量. 分析:缩点以后,找出新图的树的直径,将这两点连接即可. 但是题目有个note:两点之间可能有重边!而用普通的vector保存边的话,用v!=fa的话是没办法让重边访问的,因此,使用数组模拟邻接表的方法来储存边. 这样,只要访问了一条边以后,令E[i].vis=E[i^1].vis=1即可,这样可以防止无向图的边和重边搞混.原理就是按位异或,一个奇数^1变为比它小1的偶数,反之亦然:如5^1=4,4^1=5. 具体见代码: 1 #include

hdoj 4612 Warm up【双连通分量求桥&amp;&amp;缩点建新图求树的直径】

Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 5093    Accepted Submission(s): 1131 Problem Description N planets are connected by M bidirectional channels that allow instant transport

HDU 4612 Warm up(双连通分量缩点+求树的直径)

思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度. 树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v,一定是直径的一个端点(证明从略),第二次以点v为开头进行bfs,求出的最后一个点,就是直径的另一个端点,记录深度就是我们要求的长度.我这里是使用的bfs+dfs,是一样的,少开一个deep数组,节省一下空间吧…… 其实我一开始是不会求的,我以为随便一个叶子节点就可以做端点,交上去WA,当时还好奇感觉

HDU 4612 双联通分量+树的直径

点击打开链接 题意:给一个无向联通图,里面可能有重边,问添加一条边后,使得图中的桥最小,将桥的数量输出 思路:刚刚读完题,就有了思路去写,无非就是将联通图双联通分量后缩点,然后求一条最长的路,首尾相连,肯定将更多的桥包含使得这些桥不再是桥,很好想的题,但是错了20+什么鬼,md重边这么难处理,醉了~~~,之前的做法是将重边全部找出来,希望数据弱点水过去算了,TLE好样的,那么我们在处理桥的时候,也就是找桥的时候,如果是桥,我们将这条边标记一下,然后找所有边时加上就行了,在一个就是找树的直径,两次

HDU 4612——Warm up——————【边双连通分量、树的直径】

Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4612 Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel bet

hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个. #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map&g

HDU 4738 --Caocao&#39;s Bridges 【无向图边双联通 &amp;&amp; 求权值最小的桥 &amp;&amp; 模板】

Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2641    Accepted Submission(s): 855 Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. B

(求树的直径)Warm up -- HDU -- 4612

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 给一个无向图, 加上一条边后,求桥至少有几个: 那我们加的那条边的两个顶点u,v:一定是u,v之间含有桥的数量最多,然后uv之间的桥都没了,剩下的就是要求的结果: 树的直径的定义刚好就是两个节点之间含有最多的边: 下面是有关树的直径的知识: 这个题目需要手动扩展,不然会爆栈,而且手动扩展的话要用C++提交. 代码: #pragma comment(linker, "/STACK:1024000

Hdu 4612 Warm up (双连通分支+数的直径)

题目链接: Hdu 4612 Warm up 题目描述: 给一个无向连通图,问加上一条边后,桥的数目最少会有几个? 解题思路: 题目描述很清楚,题目也很裸,就是一眼看穿怎么做的,先求出来双连通分量,然后缩点重新建图,用bfs求树的直径,直径的长度就是减去桥的数目. 这个题目需要手动扩展,而且手动扩展的话要用C++提交,G++re哭了. 1 #include <cstdio> 2 #include <queue> 3 #include <cstring> 4 #inclu