hdu 4587 TWO NODES

题意:给出一个无向图,删除两个点让剩余的图的连通分量的数量最大。

思路:考虑每一个点,尝试将其删除,然后计算剩余的连通分量的个数,对于每个连通分量,再求删除某一个点所能增加的最多的连通分量的数量。对于第一步,直接标记一下要删除的点,然后dfs计算一下连通分量的个数即可,对于第二歩,如果再一个一个删肯定要超时了,由于要在一个连通分支中删除一个点,那么这个点要尽可能是割点,可以考虑一下求割点的过程,用tarjan求割点的时候,当lowv>=pre[u]的时候,则说明u是割点,画个图的话应该能理解好一些,没当遇到这种情况,那么删除u的时候,就会增加一个连通分量,这样的话就可以在求割点的时候计算出删除这个割点会增加多少连通分量了,这样的话,答案就能计算出来了,另外还有一些特殊情况需要特判,比如一个连通分支中没有割点的情况。

 

代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=5000+10;
int pre[maxn],vis[maxn],dfs_clock;
int ans,ban,total,step,n,m,temp;
vector<int>G[maxn];
int tarjan(int u,int fa)
{
    bool iscut=false;
    int child=0,cutnum=0;
    int lowu=pre[u]=++dfs_clock;
    for(int i=0;i<G[u].size();++i)
    {
        int v=G[u][i];
        if(v==ban) continue;
        if(!pre[v])
        {
            child++;
            int lowv=tarjan(v,u);
            lowu=min(lowu,lowv);
            if(lowv>=pre[u])
            {
                iscut=true;
                cutnum++;
            }
        }
        else if(pre[v]<pre[u]&&v!=fa)
           lowu=min(lowu,pre[v]);
    }
    if(fa<0&&child==1) iscut=false;
    if(child==0&&fa==-1) ans=max(ans,total-1);
    if(iscut)
      ans=max(ans,total+cutnum-(int)(fa==-1));
    return lowu;
}
void dfs(int u)
{
    temp++;
    vis[u]=step;
    for(int i=0;i<G[u].size();++i)
    {
        int v=G[u][i];
        if(vis[v]!=step&&v!=ban)
           dfs(v);
    }
}
void find_conn(int x)
{
    step++;
    total=0;
    ban=x;
    bool flag=false;
    for(int i=0;i<n;++i)
    {
        if(vis[i]!=step&&i!=ban)
        {
            temp=0;
            dfs(i);
            total++;
            if(temp>=2) flag=true;
        }
    }
    if(flag) ans=max(ans,total);
    memset(pre,0,sizeof(pre));
    dfs_clock=0;
    for(int i=0;i<n;++i)
      if(!pre[i]&&i!=ban) tarjan(i,-1);
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(~scanf("%d%d",&n,&m))
    {
        int a,b;
        for(int i=0;i<n;++i) G[i].clear();
        for(int i=0;i<m;++i)
        {
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
        memset(vis,0,sizeof(vis));
        ans=0;step=0;
        for(int i=0;i<n;++i)
           find_conn(i);
        printf("%d\n",ans);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值