4 5 0 1 1 2 2 3 3 0 0 2
2
题意:去掉两个点,让原图的强连通分量最大。
思路:暴力解决这题真的够呛。。所以先去枚举掉一个点,然后用tarjan判断割点的方法,如果被判断为割点说明强连通分量要增加一了,存到cut数组里,最后算最大值就好了。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<stack> using namespace std; typedef long long ll; const int N=5010; struct data { int to,next; } tu[N*N]; int head[N],low[N],dfn[N];///dfn[]记录某个点被访问到的次数,low[]记录某个点或其子树回边的最小步数的点 int cut[N];///是否为割点且该点连接边的数量 int ip; int step,rt_son,scc_cnt; void init() { ip=0; memset(head,-1,sizeof(head)); } void add(int u,int v) { tu[ip].to=v,tu[ip].next=head[u],head[u]=ip++; } void tarjan(int u,int del) { //cout<<u<<' '; dfn[u] = low[u] = step++; for(int i = head[u]; i!=-1 ; i=tu[i].next) { int to = tu[i].to; if(to==del)continue; if(!dfn[to])///表示未被访问的点 { tarjan(to,del); low[u]=min(low[u],low[to]); if(low[to]>=dfn[u]) cut[u]++; } else low[u]=min(low[u],dfn[to]); } } void solve(int n) { int ans=0; for(int j=1; j<=n; j++) { memset(dfn, 0, sizeof(dfn)); for(int i=1; i<=n; i++) cut[i]=1; step = 1; int sum=0; for (int i = 1; i <=n; i++) if (i!=j&&!dfn[i]) { sum++; cut[i]=0; tarjan(i,j); } for(int i=1; i<=n; i++) if(i!=j) ans=max(ans,sum+cut[i]-1); } printf("%d\n",ans); } int main() { int m,n; while(~scanf("%d%d",&n,&m)) { init(); while(m--) { int a,b; scanf("%d%d",&a,&b); a++,b++; add(a,b); add(b,a); } solve(n); } return 0; }