HDU - 4587
给一张 N个点的无向图,要求删掉两个点以及与其相连的边
使得剩下的图中的连通分量的数量最多
其中 3≤N≤5000
思路很直接,直接暴力枚举删掉的第一个点,打上标记
然后在剩下的图中找割点,统计删掉割点后增加的连通分量的数量
最后更新答案就好
统计的删掉割点的后连通块数量的方式,就是把 cutv[u]=1改为 cutv[u]++
然后加上一个包含父亲的连通分量,特判一下如果是根就不加
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Pow2(a) (a*a)
const int maxn=5e3+10;
struct Edge
{
int u,v,nxt;
};
int edn;
Edge edge[2*maxn];
int last[maxn];
int N,M;
int ban[maxn];
int cutv[maxn];
int dfst,dfsn[maxn],lown[maxn],sonc[maxn];
void adde(int,int);
int Tarjan(int,int);
int main()
{
while(~scanf("%d%d", &N, &M))
{
edn=0;
MST(last,-1);
for(int i=0; i<M; i++)
{
int u,v;
scanf("%d%d", &u, &v);
adde(u,v);
adde(v,u);
}
int ans=0;
for(int i=0; i<N; i++)
{
ban[i]=1;
dfst=0;
int ball=0;
CLR(cutv);CLR(dfsn);CLR(sonc);
for(int j=0; j<N; j++)
{
if(ban[j]) continue;
if(!dfsn[j])
{
ball++;
Tarjan(j,-1);
}
}
int tmax=0;
for(int j=0; j<N; j++) tmax=max(cutv[j], tmax);
ans=max(ans, ball+tmax-1);
ban[i]=0;
}
printf("%d\n", ans);
}
return 0;
}
void adde(int u, int v)
{
edge[edn].u=u;
edge[edn].v=v;
edge[edn].nxt=last[u];
last[u]=edn++;
}
int Tarjan(int u, int f)
{
dfsn[u]=++dfst;
lown[u]=dfst;
for(int e=last[u]; ~e; e=edge[e].nxt)
{
int v=edge[e].v;
if(v==f||ban[v]) continue;
if(dfsn[v])
{
lown[u]=min(lown[u],dfsn[v]);
}
else
{
sonc[u]++;
Tarjan(v,u);
lown[u]=min(lown[u], lown[v]);
if(lown[v]>=dfsn[u])
{
cutv[u]++;
}
}
}
if(~f) cutv[u]++; //加上包含父亲的连通分量
return lown[u];
}