hdu 4587 2013南京邀请赛B题/ / 求割点后连通分量数变形。

本文探讨如何通过去除无向图中的两个不同节点,最大化连通分量的数量,并详细介绍了使用tarjan算法进行割点搜索的方法。文章涵盖了原图可能不连通的情况,以及如何处理只有一个节点的连通分量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:求一个无向图的,去掉两个不同的点后最多有几个连通分量。

 思路:枚举每个点,假设去掉该点,然后对图求割点后连通分量数,更新最大的即可。算法相对简单,但是注意几个细节:

1:原图可能不连通。

2:有的连通分量只有一个点,当舍去该点时候,连通分量-1;

复习求割点的好题!



#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n,m;
vector<vector<int> >e(10010);
int dfn[5010];int low[5010];int vis[5010];
int times=0;
int subset[5010];
int root=0;
int rf=0;
int son=0;
void tarjan(int u,int fa)     //无向图tarjan记录父亲  
{
    if(u==rf)return;          //是被枚举的点,舍去(从图中删去)。
    dfn[u]=low[u]=times++;
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        if(v==rf)continue;     // 这里注意,舍去的点不要了
        if(!vis[v])
        {
            vis[v]=1;
            tarjan(v,u);
            if(low[v]<low[u])low[u]=low[v];
            if(u==root)                   //求割点是根的情况
              {
                  son++;
              }
            else                  // 其他情况
            {
                if(dfn[u]<=low[v])    //subset【u】+1记录 以u为割点后形成的连通分量数
                    subset[u]++;
            }

        }
        else if(v!=fa)         //条件注意
        {
            if(dfn[v]<low[u])low[u]=dfn[v];
        }
    }
    return ;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0;i<=n;i++)
           {
             dfn[i]=low[i]=subset[i]=vis[i]=0;
             e[i].clear();
           }
        int ta,tb;
      for(int i=0;i<m;i++)
      {
          scanf("%d%d",&ta,&tb);
           e[ta].push_back(tb);
           e[tb].push_back(ta);
      }
      int maxx=0;
      for(int i=0;i<n;i++)   //枚举每个点
      {
          rf=i;               //i舍去
          vis[rf]=1;
          int scc=0;
          int maxson=0;
          for(int iii=0;iii<n;iii++)          //考虑原图不连通!
             {
                 if(!vis[iii])
                 {
                     vis[iii]=1;
                     root=iii;
                     tarjan(iii,-1);
                     scc++;                     //连通分量数
                     if(son>maxson)maxson=son;    //求出每个连通分量的根的最大的son
                     son=0;                         //每个连通分量要更新son
                 }
             }
            if(e[i].size()==0)scc--;    // 注意点!!!:该连通分量只有一个点!舍去的话就没了。
          for(int ii=0;ii<n;ii++)             //取最大的
          {
              if(scc+subset[ii]+1-1>maxx)maxx=scc+subset[ii]+1-1;
          }
          if(scc+maxson-1>maxx)maxx=maxson+scc-1;   
          for(int j=0;j<n;j++)    //不忘更新!
          {
              dfn[j]=low[j]=subset[j]=vis[j]=0;
          }
          son=times=0;
      }
      cout<<maxx<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值