题意:给你一个连通的无向图,现在问你最少在该图中添加几条边,能使得该图变成边双连通图?
思路:
思路主要参照这两个博客
http://blog.csdn.net/u013480600/article/details/31004741
http://blog.csdn.net/lyy289065406/article/details/6762370
首先要知道边双连通分量是不会有桥的,那么只需要在dfs的时候求出每一个结点low值,low值相同的属于同一个边双连通分量,而不同的则是另外一个边双连通分量。然后采取的是一个缩点的方法,将同一个边双连通分量当作是一个点来处理,这样只需要在这些“点”加边就能使这些缩点也成为边双连通
那么我们对于一棵树需要添加几条边才能使得它变成边双连通的呢?
有以下结论:对于一棵无向树,我们要使得其变成边双连通图,需要添加的边数 == (树中度数为1的点的个数+1)/2
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
using namespace std;
#define maxn 5005
#define LL long long
int cas=1,T;
int n,m;
int sum = 0;
int degree[maxn];
int dfs_clock; //时钟,每访问一个结点增1
vector<int>G[maxn]; //图
int pre[maxn]; //pre[i]表示i结点被第一次访问到的时间戳,若pre[i]==0表示还未被访问
int low[maxn]; //low[i]表示i结点及其后代能通过反向边连回的最早的祖先的pre值
bool iscut[maxn]; //标记i结点是不是一个割点
int cut[maxn]; //切割这个结点后的儿子数
//求出以u为根节点(u在DFS树中的父节点是fa)的树的所有割点和桥
//初始调用dfs(root,-1)
int dfs(int u,int fa)
{
int lowu=pre[u]=++dfs_clock;
int child = 0; //子结点数目
for (int i = 0;i<G[u].size();i++)
{
int v = G[u][i];
if (!pre[v])
{
child++; //未访问过的结点才能算是u的孩子
int lowv = dfs(v,u);
lowu = min(lowu,lowv);
/* if (lowv >=pre[u])
{
iscut[u]=1; //u是割点
cut[u]++;
if (lowv > pre[u]) //(u,v)边时桥
printf("qiao")
}*/
}
else if (pre[v] <pre[u] && v!=fa) //v!=fa确保了(u,v)是从u到v的反向边
{
lowu = min(lowu,pre[v]);
}
}
/*if (fa <0) //若u是根
{
cut[u]--;
}*/
return low[u]=lowu;
}
void init()
{
dfs_clock = 0;
sum=0;
memset(pre,0,sizeof(pre));
// memset(iscut,0,sizeof(iscut));
memset(cut,0,sizeof(cut));
memset(degree,0,sizeof(degree));
for (int i = 0;i<=n;i++)
G[i].clear();
}
int main()
{
scanf("%d%d",&n,&m);
init();
for (int i = 0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,-1); //求出所有结点的low值,每个不同的low值代表一个边双连通分量
for (int i = 1;i<=n;i++)
{
for (int j = 0;j<G[i].size();j++)
{
int v = G[i][j];
if (low[i]!=low[v]) //如果这里写的是degree[low[v]]++,degree[low[u]]++,则记得要除以二
degree[low[v]]++;
}
}
int cnt = 0;
for (int i = 1;i<=n;i++)
if (degree[i]==1)
cnt++;
printf("%d\n",(cnt+1)/2);
//freopen("in","r",stdin);
//scanf("%d",&T);
//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
return 0;
}