题意:

给定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

*/