hdu4587 TWO NODES 求割点

/*
    在一个图中,删除两个点以后,问图最多能变成多少块?
    思路:先枚举删除的第一个点del,然后从剩下的点中dfs求割点,iscut[u]记录有多少个连通分支可以使得u成为割点,
          那么删除u后该块就被分为了iscut[u]+1块(根节点为割点则应被分为iscut[u]块,为保持形式统一令iscut[root]--),
          在dfs求割点的同时求出删去del之后整个图将被分为的块数res,则res+iscut[u]则为当前的块数ans,在枚举删除点的
          过程当中求出最大的ans即为答案。
          
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
const int maxn = 5000 + 5;
int low[maxn],pre[maxn],iscut[maxn];
int n,m,del,dfs_clock;
vector<int>G[maxn];
int dfs(int u,int fa)
{
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;
    for(int i=0;i<G[u].size();i++){
        int v = G[u][i];
        if(v==del)  continue;
        if(!pre[v]){
            ++child;
            int lowv = dfs(v,u);
            lowu = min(lowu,lowv);
            if(lowv >= pre[u]){
                ++iscut[u];       //每当有一个子分支可以使u为割点,++iscut[u];
            }
        }
        else if(pre[v]<pre[u] && v != fa){
            lowu = min(lowu,pre[v]);//一开始wa的不明所以,这里写成了 int lowu = min(lowu,pre[v]);
        }
    }
    if(fa<0)  --iscut[u];           //对于根节点,为保持形式统一令--iscut[u]
    low[u] = lowu;
//    if(fa<0&&iscut[u])  ans = max(ans,iscut[u]);
//    else if(fa>0&&iscut[u])     ans = max(ans,iscut[u]+1);
    return lowu;
}
int main()
{
    //freopen("D:\\professional debugging\\in6.txt","r",stdin);
    //freopen("D:\\professional debugging\\out62.txt","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF){
        int x,y;
        for(int i = 0;i<=n;i++)     G[i].clear();
        for(int i = 0;i<m;i++){
            scanf("%d%d",&x,&y);
            G[x+1].push_back(y+1);
            G[y+1].push_back(x+1);
        }
        int res,ans=-1;
        for(del = 1;del<=n;++del){
            mem(pre,0);     mem(low,0);     mem(iscut,0);
            dfs_clock = 0;
            res = 0;
            for(int i = 1;i<=n;i++){
                if(!pre[i]&&i!=del){
                    dfs(i,-1);
                    ++res;
                }
            }
            for(int i=1;i<=n;i++){
                if(i!=del){
                    ans = max(ans,res + iscut[i]);
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值