题意:给出n个顶点,m条边,求至少添加几条边使这个图为双连通图。
双连通图分为点连通和边连通图,其中他们之间还有着密切关系(具体可以根据自己需要深入了解)
首先根据题意要求和求边连通的方法简单,我们选择用边连通的方法解决问题。
将已经连通的图进行缩点,使之变成一棵树,那么最少添加的边个个数就是这棵树的(叶子节点数+1)/2;
其实我们是根据每个节点的low[i]值进行的缩点,low一样的是一个新的节点,这样我们能够找到有多少个桥,桥的个数==叶子节点个数。
缩点分析:
图中1,2,5,8分别是圈中各个节点的low值。缩点后的树为:
其中1---2, 1---5,1----8是桥,叶子节点是2,5,8
tarjan算法中改变low值得条件1看是否遍历过,2看V与f(father)关系
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
vector<int>e[1005];
int dfn[1005];
int low[1005];
int n,m,time;
void tarjan(int u,int f)
{
int i,v;
dfn[u]=low[u]=++time;
for(i=0;i<e[u].size();i++)
{
v=e[u][i];
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(v!=f)
{
low[u]=min(low[u],dfn[v]);
}
}
}
int main()
{
int i,j,u,v;
int in[1005],out[1005];
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
tarjan(1,1);
int d[1005]={0};
for(i=1;i<=n;i++)
{
for(j=0;j<e[i].size();j++)
{
v=e[i][j];
if(low[i]!=low[v])
d[low[i]]++;
}
}
int num=0;
for(i=1;i<=n;i++)
{
if(d[i]==1)
num++;
}
printf("%d\n",(num+1)/2);
return 0;
}