长期用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; }