1 /*
2 题意:给出一个无向图,求两个点,去除这两个点之后的连通分量数目最大
3
4 题解:无向图求割点
5 一开始在思考的时候想要先求出最大和次大的割点,然后发现两个割点如果相连的话比较难判断,在网上搜索题解发现
6 是通过先枚举所有点,然后再求出最大割点,然后求出最终答案,略显暴力,但是12s的时间,估计是绰绰有余了。。
7 */
8 #include<iostream>
9 #include<cstdio>
10 #include<cstring>
11
12 using namespace std;
13
14 const int MAXV = 5005;
15
16 int dfn[MAXV],low[MAXV],head[MAXV],cut[MAXV];
17 bool vis[MAXV];
18 int cnt,EN;
19
20 struct Edge
21 {
22 int to,nxt;
23 }edge[MAXV<<1];
24
25 void addedge(int cu,int cv)
26 {
27 edge[EN].to = cv;
28 edge[EN].nxt = head[cu];
29 head[cu] = EN++;
30 }
31
32 void Tarjan(int u,int c) // 求割点
33 {
34 vis[u] = true;
35 dfn[u] = low[u] = ++cnt;
36 for(int i = head[u]; i != -1; i = edge[i].nxt)
37 {
38 int v = edge[i].to;
39 if (v == c) // 此处通过特判去除c点
40 continue;
41 if (dfn[v] == 0) {
42 Tarjan(v,c);
43 low[u] = min(low[u], low[v]);
44 if (low[v] >= dfn[u])
45 {
46 cut[u]++;
47 }
48 }
49 else if (vis[v])
50 low[u] = min(low[u], dfn[v]);
51 }
52 }
53
54 int main(void)
55 {
56 int n,m;
57 while(~scanf("%d%d",&n,&m))
58 {
59 memset(head,-1,sizeof(head));
60 EN=0;
61 while (m--)
62 {
63 int u,v;
64 scanf("%d%d",&u,&v);
65 addedge(u,v);
66 addedge(v,u);
67 }
68
69 int ans = 0;
70 for(int i=0; i<n; i++)
71 {
72 // 遍历分别去除n个点(在搜索过程中特判实现),然后再求割点使得切割数量最大
73 memset(dfn,0,sizeof(dfn));
74 memset(vis,false,sizeof(vis));
75 for(int j=0; j<n; j++)
76 cut[j] = 1;
77 int sum = 0; // 记录总共有多少个连通分量
78 cnt = 0;
79 for(int j=0; j<n; j++)
80 {
81 if (i != j && !vis[j])
82 {
83 sum++;
84 cut[j] = 0; // 当前以j为根结点搜索,因此需要赋0
85 Tarjan(j,i);
86 }
87 }
88 for(int j=0; j<n; j++)
89 if (j != i)
90 {
91 ans = max(ans,sum+cut[j] - 1); // 求出符合的割点
92 }
93 }
94 printf("%d\n",ans);
95 }
96 return 0;
97 }