hdu 4612 Tarjan求桥数 + 求树的直径

题意:

一个有重边的无向连通图,添加一条边后最少剩几个桥。2  <= n <= 200000 , 1 <= m <= 1000000。

题解:

1.先用Tarjan缩点后求出桥数,然后原图就变成了一个树,对于一颗树,添加1条边后剩的最少桥数 = 总桥数 - 直径

树的桥数 = 边数。

2.2次dfs求树的直径:从任意点出发,求出距离该点最远的点pos ,再从pos出发,找到距离pos最远的点的距离ans。ans即为直径。无向图为了避免标记,传递参数时把父节点的序号标上。

3.用vector会MLE,所以需要用前向星。又因为是无向图且有重边,所以需要在前向星中加入flag。edge[i]遍历过后,反边不再遍历,即edge[i].flag = edge[i^1].flag = 0,第i条边和第i^1条边是互为反边。重边视为不同边

#include <bits/stdc++.h>
#define N 200005
#define M 1000005
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
int n , m ;
int vis[N] ;
int low[N] ;
int dfn[N] ;
int s[N] ;
int id[N] ;
int top1 ;
int lay ;
int head[N] , head1[N] ;
int cnt ;
int tcc_num ;
int pos , ans ;
int bridge_num ;
int bridge[M][2] ;
struct Edge
{
    int to , next ;
    bool flag ;
} edge[M << 1] ;
void Tarjin(int u)
{
    int i , j , v ;
    lay ++ ;
    vis[u] = 1 ;
    low[u] = lay ;
    dfn[u] = lay ;
    s[++ top1] = u ;
    for(i = head[u] ; i != -1 ; i = edge[i].next)
    {
        if(!edge[i].flag)
           continue ;
        edge[i].flag = edge[i ^ 1].flag = 0 ;
        v = edge[i].to ;
        if(vis[v] == 0)
        {
          Tarjin(v) ;
          if(dfn[u] < low[v])
          {
                bridge_num ++ ;
                bridge[bridge_num][0] = u ;
                bridge[bridge_num][1] = v ;
          }
        }
        if(vis[v] == 1)
          low[u] = min(low[u] , low[v]) ;
    }
    if(low[u] == dfn[u])
    {
        tcc_num ++ ;
        while(s[top1] != u)
        {
            id[s[top1]] = tcc_num ;
            vis[s[top1]] = 2 ;
            top1 -- ;
        }
        id[s[top1]] = tcc_num ;
        vis[s[top1]] = 2 ;
        top1 -- ;
    }
}
int dfs(int u , int fa , int d)
{
    int i , j , v ;
    if(d > ans)
    {
        ans = d ;
        pos = u ;
    }
    for(i = head[u] ; i != -1 ; i = edge[i].next)
    {
        v = edge[i].to ;
        if(fa == v)
           continue ;
        dfs(v , u , d + 1) ;
    }
}
void cal()
{
    int i , j ;
    ans = 0 ;
    dfs(1 , 1 , 0) ;
    ans = 0 ;
    dfs(pos , pos , 0) ;
    printf("%d\n" , bridge_num - ans) ;
}
void addedge(int u , int v)
{
    edge[cnt].flag = 1 ;
    edge[cnt].to = id[v] ;
    edge[cnt].next = head[id[u]] ;
    head[id[u]] = cnt ++ ;
    edge[cnt].flag = 1 ;
    edge[cnt].to = id[u] ;
    edge[cnt].next = head[id[v]] ;
    head[id[v]] = cnt ++ ;
}
void change()
{
    int i , j ;
    cnt = 0 ;
    memset(head , -1 , sizeof(head)) ;
    for(i = 1 ; i <= bridge_num ; i ++)
       addedge(bridge[i][0] , bridge[i][1]) ;
}
int main()
{
    int i , j ;
    int u , v ;
    while(scanf("%d%d" , &n , &m) && !(n == 0 && m == 0))
    {
      cnt = 0 ;
      memset(vis , 0 , sizeof(vis)) ;
      memset(head , -1 , sizeof(head)) ;
      for(i = 1 ; i <= n ; i ++)
	      id[i] = i ; 
      for(i = 1 ; i <= m ; i ++)
      {
        scanf("%d%d" , &u , &v) ;
        addedge(u , v) ;
      }
      lay = top1 = 0 ;
      tcc_num = bridge_num = 0 ;
      Tarjin(1) ; //缩点
      change() ; //新建一个树
      cal() ;
    }
}

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/88085608