这是一题求边—双连通的题目 , 题目给出一个无向图 , 问最少还需要多少边 , 才能让这个图变成边—双连通图 。
解法:
1、 先求出所有桥 ,然后再用dfs去遍历图,且不能经过桥, 这样就能把图中的所有边连通分量求出
2、让后再把所有边连通分量缩成一个点 , 用桥去连接这些点 , 最小边 = (a + b*2 + 1)/2 , a 表示新构成的图中度为1的点 , b是表示度为2的点。
缩点的方法:
把第一个连通分量中的所有点都用bcc_cnt来标记 , 而下一个连通分量就用bcc_cnt+1 , 来标记 。 这样就区分了所有连通分量 , 只要原图中一条边的两点在标记中的数不一样 , 那么这两个点的度就加1;
这类似于 , 并查集的父亲节点 , 判断是不是同一个连通图。
需要用的定理:
1、所有边—连通分量是没有公共点的 。
2、缩点之后的最小边为(a + b*2 + 1)/2 。
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1010 ;
int pre[MAXN] , bccno[MAXN] , iscnt[MAXN];
vectorgrap[MAXN] ;
int n , m , dfs_clock , bcc_cnt ;
int xy[MAXN][MAXN] , p[MAXN];
void init()
{
for(int i = 0 ; i <= n; i++)
grap[i].clear();
memset(xy ,0 , sizeof(xy));
}
int dfs1(int u , int fa)
{
int lowu = pre[u] = ++dfs_clock;
for(int i = 0 ; i < grap[u].size() ; i++)
{
int v = grap[u][i];
if(!pre[v])
{
int lowv = dfs1(v , u);
if(lowu < lowv)
lowu = lowv;
if(lowv > pre[u])
xy[u][v] = xy[v][u] = 1;
}
if(pre[v] < pre[u] && v != fa)
if(pre[v] < lowu)
lowu = pre[v];
}
return lowu;
}
void dfs2(int u)
{
p[u] = bcc_cnt;
iscnt[u] = 1;
for(int i = 0 ; i < grap[u].size(); i++)
{
int v = grap[u][i];
if(!iscnt[v] && !xy[u][v])
dfs2(v);
}
}
void bcc_find()
{
memset(pre , 0 , sizeof(pre));
memset(bccno , 0 ,sizeof(bccno));
memset(iscnt , 0 , sizeof(iscnt));
dfs_clock = bcc_cnt = 0;
int i
;
for(i = 1; i <= n; i++)
if(!pre[i])
dfs1(i , -1);
for(i = 1; i <= n; i++)
{
if(!iscnt[i]) bcc_cnt++ , dfs2(i);
// 标记每个连通分量 , 并构图
}
}
int main()
{
while(scanf("%d %d" , &n , &m)
!= EOF)
{
init();
int i , j , x , y;
for(i = 0 ; i < m; i++)
{
scanf("%d %d" , &x , &y);
grap[x].push_back(y);
grap[y].push_back(x);
}
bcc_find();
memset(iscnt , 0 , sizeof(iscnt));
for(i = 1; i <= n; i++)
for(j = 0 ; j < grap[i].size() ; j++)
if(p[i] != p[grap[i][j]])
// 找新图中每个点的度数
{
iscnt[p[i]]
+= 1;
iscnt[p[grap[i][j]]]
+= 1;
}
x = y = 0;
for(i = 1; i <= bcc_cnt ; i++)
{
//cout<<iscnt[i]<<endl;
if(iscnt[i] == 0)
x += 2;
if(iscnt[i]/2 == 1)
y += 1;
}
int min_bian = (x+y+1)/2;
if(bcc_cnt == 1)
min_bian = 0;
cout<<min_bian<<endl;
}
return 0;
}
解法:
1、 先求出所有桥 ,然后再用dfs去遍历图,且不能经过桥, 这样就能把图中的所有边连通分量求出
2、让后再把所有边连通分量缩成一个点 , 用桥去连接这些点 , 最小边 = (a + b*2 + 1)/2 , a 表示新构成的图中度为1的点 , b是表示度为2的点。
缩点的方法:
这类似于 , 并查集的父亲节点 , 判断是不是同一个连通图。
需要用的定理:
1、所有边—连通分量是没有公共点的 。
2、缩点之后的最小边为(a + b*2 + 1)/2 。
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1010 ;
int pre[MAXN] , bccno[MAXN] , iscnt[MAXN];
vectorgrap[MAXN] ;
int n , m , dfs_clock , bcc_cnt ;
int xy[MAXN][MAXN] , p[MAXN];
void init()
{
}
int dfs1(int u , int fa)
{
}
void dfs2(int u)
{
}
void bcc_find()
{
}
int main()
{
}