题意:
给定一个n个点的无向图(n >= 3),要求去掉两个点后造成最多的连通块个数。
思路:
枚举一个必去的点,然后寻找一个最优的割点造成最多的连通块。其实就是一个割点变形,在求割点的过程直接记录当前割点去掉之后能够造成多少连通块,想复杂了,用了点双连通分量的板子= =,wa点:当必定去掉的一个点去掉之后,每个点都成为了一个连通块,此时是寻找不到割点的,所以去掉一个任意点,实际是去掉了一个连通块,特判一下就好。(数据贼水,判断m等于0时输出n-2也能过...)
割点变形代码1,点双连通分量代码2。
代码1:
#include
using namespace std;
const int maxn = 5005;
const int maxm = 10005;
struct node{int u, v, next;} edge[maxm];
int mark[maxm];
int no, head[maxn];
int n, m, ans;
int yltd;
int index, dfn[maxn], low[maxn];
int cnt[maxn];
void init()
{
no = 0;
memset(head, -1, sizeof head);
}
inline void add(int u, int v)
{
edge[no].u = u, edge[no].v = v;
edge[no].next = head[u];
head[u] = no++;
}
void tarjan(int u, int fa)
{
int child = 0;
dfn[u] = low[u] = ++index;
for(int k = head[u]; k+1; k = edge[k].next)
{
if(mark[k]) continue;
int v = edge[k].v;
if(!dfn[v])
{
++child;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(fa != -1 && low[v] >= dfn[u])
++cnt[u];
if(fa == -1 && child > 1)
++cnt[u];
}
else if(v != fa) low[u] = min(low[u], dfn[v]);
}
}
int find(int bad)
{
index = yltd = 0;
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
memset(cnt, 0, sizeof cnt);
for(int i = 1; i <= n; ++i)
if(bad != i && !dfn[i]) tarjan(i, -1), ++yltd;
int res = 0;
for(int i = 1; i <= n; ++i)
if(bad != i) res = max(res, cnt[i]);
return res+yltd;
}
void work()
{
ans = 0;
for(int i = 1; i <= n; ++i)
{
memset(mark, 0, sizeof mark);
int tot = 0;
for(int k = head[i]; k+1; k = edge[k].next)
mark[k] = mark[k^1] = 1, ++tot;
if(tot == m)
{
ans = n-2; break;
}
ans = max(ans, find(i));
}
printf("%d\n", ans);
}
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d %d", &n, &m))
{
init();
for(int i = 1; i <= m; ++i)
{
int u, v;
scanf("%d %d", &u, &v);
add(u+1, v+1); add(v+1, u+1);
}
work();
}
return 0;
}
代码2:
#include
using namespace std;
const int maxn = 5005;
const int maxm = 10005;
struct node{int u, v, next;} edge[maxm];
int mark[maxm];
int no, head[maxn];
int n, m, ans;
int add_bcc[maxn];
int index;
int yltd;
int num[maxn], low[maxn];
int iscut[maxn];
int bccno[maxn], bcc_cnt;
stack S;
vector bcc[maxn];
void init()
{
no = 0;
memset(head, -1, sizeof head);
}
inline void add(int u, int v)
{
edge[no].u = u, edge[no].v = v;
edge[no].next = head[u];
head[u] = no++;
}
void tarjan(int u, int fa)
{
int child = 0;
num[u] = low[u] = ++index;
for(int k = head[u]; k+1; k = edge[k].next)
{
if(mark[k]) continue;
int v = edge[k].v;
if(!num[v])
{
S.push(edge[k]);
++child;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= num[u])
{
iscut[u] = 1;
++add_bcc[u];
++bcc_cnt;
bcc[bcc_cnt].clear();
while(true)
{
node tp = S.top(); S.pop();
if(bccno[tp.u] != bcc_cnt)
{
bcc[bcc_cnt].push_back(tp.u);
bccno[tp.u] = bcc_cnt;
}
if(bccno[tp.v] != bcc_cnt)
{
bcc[bcc_cnt].push_back(tp.v);
bccno[tp.v] = bcc_cnt;
}
if(tp.u == edge[k].u && tp.v == edge[k].v)
break;
}
}
}
else if(num[v] < num[u] && v != fa)
{
S.push(edge[k]);
low[u] = min(low[u], num[v]);
}
}
if(fa < 0)
{
if(child > 1) iscut[u] = 1, add_bcc[u] = child-1;
else iscut[u] = 0, add_bcc[u] = 0;
}
}
int find_Cut(int bad)
{
index = bcc_cnt = yltd = 0;
memset(add_bcc, 0, sizeof add_bcc);
memset(num, 0, sizeof num);
memset(iscut, 0, sizeof iscut);
memset(bccno, 0, sizeof bccno);
memset(low, 0, sizeof low);
for(int i = 1; i <= n; ++i)
if(bad != i && !num[i]) tarjan(i, -1), ++yltd;
int res = 0;
for(int i = 1; i <= n; ++i)
if(iscut[i] && bad != i)
res = max(res, add_bcc[i]);
//cout << yltd << " " << res << endl;
return res+yltd;
}
void work()
{
ans = 0;
for(int i = 1; i <= n; ++i)
{
memset(mark, 0, sizeof mark);
int tot = 0;
for(int k = head[i]; k+1; k = edge[k].next)
mark[k] = mark[k^1] = 1, ++tot;
if(tot == m)
{
ans = n-2;
break;
}
else
ans = max(ans, find_Cut(i));
}
printf("%d\n", ans);
}
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d %d", &n, &m))
{
init();
for(int i = 1; i <= m; ++i)
{
int u, v;
scanf("%d %d", &u, &v);
add(u+1, v+1); add(v+1, u+1);
}
work();
}
return 0;
}
继续加油~