hdu 4587 割点 2013 ACM-ICPC南京赛区全国邀请赛

长期用tarjan,每次一上来直接缩点,弄得连基本的割点割边都不太会,其实道理差不多的

还是tarjan的那个过程,不过不用维护一个栈

枚举删掉的第一个点,割点算法跑一遍,在跑一遍的过程中记录每个点(除了删除的那个点)和多少个连通分支相连

注意一个连通分支只有一个点的时候,删掉它,这个连通分支就没有了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 5050
int adj[N*2],head[N],edge[N*2],e,n,m,vis[N*2],deg[N];
int low[N],dfn[N],cnt,cut[N],root,insta[N];
int del;
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++cnt;
    insta[u]=1;
    int tot=0;
    for(int i=head[u];i+1;i=adj[i])
    {
        if(edge[i]==fa||edge[i]==del) continue;
        else if(dfn[edge[i]]==0)
        {
            tarjan(edge[i],u);
            low[u]=min(low[u],low[edge[i]]);
            tot++;
            if(u!=root&&low[edge[i]]>=dfn[u])
                cut[u]++;
        }
        else if(insta[edge[i]])
            low[u]=min(low[u],dfn[edge[i]]);
    }
    if(u==root)
        cut[u]=tot-1; // 当该连通分支只有一个点时为-1
    insta[u]=0;
}

void init()
{
    cnt=0;
    memset(dfn,0,sizeof(dfn));
    memset(cut,0,sizeof(cut));
    memset(insta,0,sizeof(insta));
}
void addedge(int u,int v)
{
    edge[e]=v;adj[e]=head[u];head[u]=e++;
}
int main ()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(head,-1,sizeof(head));
        e=0;
        for(int i=1,v,u;i<=m;++i)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        int ans=0;
        for(int u=0;u<n;++u)
        {
            init();
            del=u;
            int sum=0;
            for(int i=0;i<n;++i)
                if(i!=u&&!dfn[i])
            {
                root=i;sum++;
                tarjan(i,-1);
            }
            for(int i=0;i<n;++i)
                if(i!=u)
                ans=max(ans,sum+cut[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

你可能感兴趣的:(hdu 4587 割点 2013 ACM-ICPC南京赛区全国邀请赛)