題意
題目說了一堆廢話,簡單直白一點就是求割點,刪除哪個點之後連通分量最多(被刪除的哪個點不算),最開始給的圖可能就是一個不聯通的圖,最多有1萬個點,邊數不知道多少。
思路
- 由於圖可能不連通所以放在循環裏,對每個沒有時間序的點跑tarjan求割點,每跑一次tarjan就有一個聯通分量。
- 枚舉每一個點,計算刪除該點下的連通分量數目找到最大。
- 計算聯通分量直接在tarjan模板上做修改,但是要注意根節點和非根節點的連通塊數區別:根節點的連通塊是孩子數目 - 1,非根節點直接統計就可以。
- 由於邊不知道是多少,防止鏈式前向星邊數過大采用vector模擬鄰接表存圖,反正重邊無影響對割點不影響。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#pragma warning(disable:4996)
using namespace std;
const int maxn = 10005;
vector<int>e[maxn];
int dfn[maxn];
int low[maxn];
int s[maxn];
int root,cnt;
inline void clear_set()
{
for(int i = 0;i < maxn;i++){
e[i].clear();
}
cnt = 0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(s,0,sizeof(s));
}
inline void tarjan(int x,int fx)
{
dfn[x] = low[x] = ++cnt;
int son = 0;
for(int i = 0;i < e[x].size();i++){
int y = e[x][i];
if(!dfn[y]){
son++;
tarjan(y,x);
low[x] = min(low[x],low[y]);
if(low[y] >= dfn[x] && x != root){
s[x]++;
}
}
else if(y != fx && dfn[y] < dfn[x]){
low[x] = min(low[x],dfn[y]);
}
}
if(x == root){
s[x] = son - 1;
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n == 0 && m == 0) break;
clear_set();
for(int i = 0;i < m;i++){
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
int sum = 0;
for(int i = 0;i < n;i++){
if(!dfn[i]){
root = i;
sum++; //連通分量數目
tarjan(i,-1);
}
}
int ans = 0;
for(int i = 0;i < n;i++){
ans = max(ans,sum+s[i]);
}
printf("%d\n",ans);
}
return 0;
}
願你走出半生,歸來仍是少年~