poj 3352
2013-12-14 20:03
197 查看
这是一题求边—双连通的题目 , 题目给出一个无向图 , 问最少还需要多少边 , 才能让这个图变成边—双连通图 。
解法:
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));
解法:
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));
相关文章推荐
- poj 1523 求图的割点
- uva 10972 边—双连通分量
- 强连通分量scc
- uva 10765(无向双连通量)
- FZU 2103 组合概率
- 我的博客今天0岁51天了,我领取了…
- poj 1325
- uva 11865 stream my contest
- uva 11865 stream my contest
- 二分图的最佳完美匹配(和一些变形…
- 有向图最小生成树——最小树形图(朱…
- 每个点与点之间的瓶颈路
- LA 5713 Qin&nbsp…
- uva 11354 Bond
- 最小生成树的一些性质和理解
- poj 2485 简单的最小生…
- 我的博客今天0岁42天了,我领取了…
- LA 4080 Warfare A…
- hdu 2433 最短路树
- 【快速】排序, T(n) = O(nlgn),O(n^2) S(n) = O(lgn) --- 不稳定