hdu 4612 无向图连通分量缩点,然后求树的最大直径

#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200100;
const int maxm = 2000100;
struct node{
    int v,next;
}edge[maxm];
struct Bridge
{
    int u,v;
}bridge[maxm];
int head[maxn],vis[maxm],fa[maxn],dfn[maxn],low[maxn],stack[maxn],in[maxn];
int id,time,num,total,top,ans;
void add_edge(int u,int v)
{
    edge[id].v = v;edge[id].next = head[u],head[u] = id++;
    edge[id].v = u;edge[id].next = head[v],head[v] = id++;
}
int min(int x,int y)
{
    return x < y ? x : y;
}
void tarjan(int u)
{//无向图找桥并缩点
    low[u] = dfn[u] = ++time;
    stack[top++] = u;
    for(int id = head[u] ; id != -1; id = edge[id].next)
    {
        int v =edge[id].v;
        if(vis[id])continue;
        vis[id] = vis[id^1] = 1;
        if( !dfn[v] )
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
            if( low[v] > dfn[u])//u经过v不能回到u,则u与v之间存在桥
            {
                bridge[total].u = u;
                bridge[total++].v = v;
            }
        }
        low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u])
    {//对连通分量进行缩点
        num++;
        int t;
        do{
            t = stack[--top];
            fa[t] = num;
        }while( t != u);
    }
}
vector<int>g[maxn];

int dfs(int u)
{//求树的最大直径
    vis[u]=1;
    int i,j,temp=0,Max=0,lMax=0;//Max为以u为根,u到的最远的叶子节点的距离,lMax为次最远距离
    for(i = 0; i < g[u].size() ; i++ ){
        int v = g[u][i];
        if(vis[v])continue;
        temp=dfs(v);
        if(temp+1>=Max){
            lMax=Max;
            Max=temp+1;
        }
        else
            if(temp+1>lMax)
                lMax=temp+1;
        if(Max+lMax>ans)
            ans=Max+lMax;
    }
    return Max;
}

int max_len()
{//求树的最大直径
    int res = 0;
    memset(vis,0,sizeof(vis));
    queue<int>que;
    que.push(1);
    vis[1] = 1;
    int tmp;
    while( !que.empty())
    {
        int u = que.front();
        que.pop();
        tmp = u;
        for( int i = 0 ; i < g[u].size(); i++)
        {
            int v = g[u][i];
            if( vis[v] )continue;
            vis[v] = 1;
            que.push(v);
        }
    }

    queue<pair<int,int> >que1;
    memset(vis,0,sizeof(vis));
    que1.push(make_pair(tmp,0));
    pair<int,int>x,y;
        vis[tmp] = 1;
    while( !que1.empty())
    {
        x = que1.front();
        que1.pop();
        for(int i = 0; i < g[x.first].size() ; i++)
        {
            int v = g[x.first][i];
            if( vis[v] )continue;
            vis[v] = 1;
            que1.push(make_pair(v,x.second+1));
            res = res > x.second ? res : x.second + 1;
        }
    }
    return res;
}
int main()
{
    int n,m,u,v;
    int i;
   // freopen("in.txt","r",stdin);
    while( ~scanf("%d%d",&n,&m) && n+m)
    {
        id = 0;
        memset(head,-1,sizeof(head));
        while( m-- )
        {
          scanf("%d%d",&u,&v);
          add_edge(u,v);
        }
        total = num = 0;
        memset(dfn,0,sizeof(dfn));
        memset(fa,-1,sizeof(fa));
        memset(vis,0,sizeof(vis));
        for(i = 1; i <= n; i++)//可以处理不连通的无向图,如果连通只需要一次即可
        {
            if( !dfn[i] )
            {
                top = time = 1;
                tarjan(i);
              //num++;
              //for( int j = 1; j <= n; j++) //特殊处理顶点的连通块
              //    if( dfn[j] && fa[j] == -1)fa[j] = num;
            }
        }
        //for( i = 1; i <= n; i++)cout << fa[i] << endl;
        for(i = 1; i <= n;i++)g[i].clear();
        int x,y;
        //建树
       // cout << total << endl;
        for( i = 0 ; i < total; i++)
        {
            x = fa[bridge[i].u];
            y = fa[bridge[i].v];
           //cout << x << " " << y << endl;
            g[x].push_back(y);
            g[y].push_back(x);
        }
        memset(vis,0,sizeof(vis));
        ans = 0;
        dfs(1);
        printf("%d\n",total - ans );
    }
    return 0;
}

  

  

转载于:https://www.cnblogs.com/LUO257316/p/3221197.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值