题意:
给定n个点m条边的无向图(保证连通)
问:至少加多少条边可以使图为双连通图)
思路:
双连通图即所有点都属于至少一个环中
显然我们先把图缩点得到一棵缩点树,问题就转成在缩点树上加最少多少条边使得图为双连通图。
对于n个节点的无根树,至少要 (1+left)/2 条边(left为叶子节点数)
#include<stdio.h>
#include<string.h>
#include<vector>
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
#define N 1005
#define M 1005
struct Edge{
int from, to, nex;
bool cut;
}edge[M*2];
int head[N], edgenum;
void addedge(int u, int v){
Edge E={u,v,head[u],false};
edge[ edgenum ] = E;
head[u] = edgenum++;
}
int n, m;
int dfn[N], low[N], tarjan_time, tar, Stack[N*5], top;
int Belong[N];
bool iscut[N];
void tarjan(int u, int fa){
dfn[u] = low[u] = ++tarjan_time;
Stack[++top] = u;
int child = 0, flag = 1;
for(int i = head[u]; ~i; i = edge[i].nex)
{
int v = edge[i].to;
if(flag && v==fa){flag = 0; continue;}
if(!dfn[v])
{
child++;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u])
{
iscut[u] = true;
if(low[v]>dfn[u])
edge[i].cut = edge[i^1].cut = true;
}
}
else low[u] = min(low[u], dfn[v]);
}
if(child == 1 && fa<0)iscut[u] = false;
if(low[u] == dfn[u])
{
tar++;
do
{
Belong[ Stack[top] ] = tar;
}while(Stack[top--] != u);
}
}
int du[N];
bool connect[N][N];
char tmp[1000];
void init(){
memset(head, -1, sizeof(head)), edgenum = 0;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(iscut, 0, sizeof(iscut));
memset(Belong, -1, sizeof(Belong));
tarjan_time = 0;
top = 0;
tar = 0;
memset(du, 0, sizeof(du));
for(int i = 0; i <= n; i++)memset(connect[i], 0, sizeof(connect[i]));
}
int main(){
int u, v;
while(~scanf("%d %d", &n, &m)){
init();
while(m--){scanf("%d %d",&u,&v); addedge(u, v), addedge(v, u);}
tarjan(1, -1);
for(int i = 0; i < edgenum; i++)if(edge[i].cut)
{
int v = edge[i].to;
du[Belong[v]]++;
}
int ans = 0;
for(int i = 1; i <= tar; i++) ans += (du[i] == 1);
printf("%d\n", (1+ans)>>1);
}
return 0;
}
/*
10 12
1 2
1 3
1 4
2 5
2 6
5 6
3 7
3 8
7 8
4 9
4 10
9 10
3 3
1 2
2 3
1 3
*/