poj3352Road Construction 边双连通+伪缩点
/*
对于边双连通分支,求法更为简单。 仅仅需在求出全部的桥以后,把桥边删除。\
原图变成了多个连通块,则每一个连通块就是一个边双连通分支。 桥不属于不论什么
一个边双连通分支,其余的边和每一个顶点都属于且仅仅属于一个边双连通分支。
一个有桥的连通图,怎样把它通过加边变成边双连通图?方法为首先求出全部的桥,
然后删除这些桥边,剩下的每一个连通块都是一个双连通子图。把每一个双连通子图收缩为一个顶点,
再把桥边加回来,最后的这个图一定是一棵树。边连通度为1。
统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。 则至少在树上加入(leaf+1)/2条边。
就能使树达到边二连通。所以至少加入的边数就是(leaf+1)/2。详细方法为,首先把两个近期公共祖先最远
的两个叶节点之间连接一条边,这样能够把这两个点到祖先的路径上全部点收缩到一起。
由于一个形成的环一定是双连通的。然后再找两个近期公共祖先最远的两个叶节点,这样一对一对找完,
恰好是(leaf+1)/2次。把全部点收缩到了一起。
*/
/*
(1) n 为顶点数, 标号从 1 開始
(2) c 为原图的邻接表, g 为 E_BCC 图的邻接表
(3) num[u] 表示原图中的点 u 属于新图中的第 num[u] 个 E_BCC
(4) edge[] 存储全部的桥
(5) 注意 pool[M] 要开得足够大以容得下新旧两个图中全部的边
(6) E_BCC 图中去掉了自环 ( 显然不存在多重边 )
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 11115;
const int M = 2000005; struct List {
int v, id;
List *next;
} pool[M], *c[N], *g[N], *pp;
//c 为原图的邻接表, g 为 E_BCC 图的邻接表
//注意 pool[M] 要开得足够大以容得下新旧两个图中全部的边
inline void add_edge(int u, int v, int id, List *c[])
{
pp->v = v;
pp->id = id;
pp->next = c[u];
c[u] = pp ++;
} struct Edge {
int u, v;
} edge[M];
//edge[] 存储全部的桥,u,v为桥的两个顶点
int n, m, label, tot, top;
int low[N], dfn[N], num[N], stack[N];
bool eflag[M];
//label时间戳,tot连通块数
//dfn用来保存时间戳(次序)编号,low保存顶点i或i的子树最早的次序编号
//num[u] 表示原图中的点 u 属于新图中的第 num[u] 个 E_BCC
void E_BCC_VISIT(int u)
{
low[u] = dfn[u] = label ++;
stack[++ top] = u;
for(List *p = c[u]; p; p = p->next) {
int v = p->v;
if(eflag[p->id]) continue;
eflag[p->id] = true;
//if(dfn[v]) { low[u] <?= dfn[v]; continue; }
if(dfn[v]){
if(low[u] > dfn[v]) low[u] = dfn[v];
continue;
}
E_BCC_VISIT(v);
//low[u] <?= low[v];
if(low[u] > low[v]) low[u]=low[v];
if(low[v] > dfn[u]) {
edge[m].u = u;//第m条桥的两个顶点u,v
edge[m ++].v = v;
++ tot;
do {
num[stack[top]] = tot;
} while( stack[top --] != v );
}
}
}
void E_BCC()
{
int i;
tot = 0;
m = 0;/////
for(i = 1; i <= n; ++ i) dfn[i] = 0, num[i] = -1;
for(i = 0; i < m; ++ i) eflag[i] = false;
for(i = 1; i <= n; ++ i)
if(dfn[i] == 0) {
label = 1;
top = -1;
E_BCC_VISIT(i);
++ tot;
while( top >= 0 ) {
num[stack[top]] = tot;
-- top;
}
}
for(i = 1; i <= tot; ++ i) g[i] = NULL;
//for(i = 1; i <= n; ++ i) {//缩点,这题用不着
// int u = num[i];//u为一个双连通分量
//for(List *p = c[i]; p; p = p->next) {
// int v = num[p->v];//v是还有一个双连通分量
//if(u != v) add_edge(u, v, 0, g);//在两个分量间建一条边
//}
//}
} int main()
{
int i, j, k;
while( scanf("%d %d", &n, &m) == 2 ) {
for(i = 1; i <= n; ++ i) c[i] = NULL;
pp = pool;
for(k = 0; k < m; ++ k) {
scanf("%d %d", &i, &j);
add_edge(i, j, k, c);
add_edge(j, i, k, c);
}
E_BCC();
if(m == 0){cout<<0<<endl; continue;}
int du[N]={0};
for(int i=0;i<m;i++){//桥即为联通块的之间的边,这里处理伪缩点
//cout<<num[edge[i].u]<<' '<<num[edge[i].v]<<endl;
du[num[edge[i].u]]++;//要用num[]映射到连通块编号上计算联通块的度
du[num[edge[i].v]]++;
}
int leaf=0;//树叶
//cout<<tot<<endl<<m<<endl;
for(int i=1;i<=tot;i++) if(du[i]==1)leaf++;
cout<<(leaf+1)/2<<endl;
//for(int i=0;i<=m;i++)printf("num[%d]:%d\n",i,num[i]);
//printf("tot:%d m:%d\n",tot,m);
}
return 0;
}
poj3352Road Construction 边双连通+伪缩点的更多相关文章
- POJ3352Road Construction(构造双连通图)sdut2506完美网络
构造双连通图:一个有桥的连通图,如何把它通过加边变成边双连通图? 一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥,然后删除这些桥边,剩下的每个连通块都是一个双连通子图.把每个 ...
- HDU4612Warm up 边双连通 Tarjan缩点
N planets are connected by M bidirectional channels that allow instant transportation. It's always p ...
- 图论--边双连通V-DCC缩点
// tarjan算法求无向图的割点.点双连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> ...
- 图论--双连通E-DCC缩点模板
// tarjan算法求无向图的桥.边双连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> ...
- POJ 3177 Redundant Paths POJ 3352 Road Construction(双连接)
POJ 3177 Redundant Paths POJ 3352 Road Construction 题目链接 题意:两题一样的.一份代码能交.给定一个连通无向图,问加几条边能使得图变成一个双连通图 ...
- POJ-3352 Road Construction,tarjan缩点求边双连通!
Road Construction 本来不想做这个题,下午总结的时候发现自己花了一周的时间学连通图却连什么是边双连通不清楚,于是百度了一下相关内容,原来就是一个点到另一个至少有两条不同的路. 题意:给 ...
- poj 3352 Road Construction【边双连通求最少加多少条边使图双连通&&缩点】
Road Construction Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10141 Accepted: 503 ...
- hdu 4612 Warm up 双连通缩点+树的直径
首先双连通缩点建立新图(顺带求原图的总的桥数,事实上因为原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首 ...
- POJ 3177 Redundant Paths (边双连通+缩点)
<题目链接> <转载于 >>> > 题目大意: 有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新 ...
随机推荐
- caffe-ssd使用预训练模型做目标检测
首先参考https://www.jianshu.com/p/4eaedaeafcb4 这是一个傻瓜似的目标检测样例,目前还不清楚图片怎么转换,怎么验证,后续继续跟进 模型测试(1)图片数据集上测试 p ...
- kentico中的page template的使用
父页面使用自己的template 子页面,也使用自己的template. 然后父页面中需要添加一个place holder. 子页面的继承,选择inherit only master page. 这样 ...
- Swift - 制作一个在线流媒体音乐播放器(使用StreamingKit库)
在之前的文章中,我介绍了如何使用 AVPlayer 制作一个简单的音乐播放器(点击查看1.点击查看2).虽然这个播放器也可以播放网络音频,但其实际上是将音频文件下载到本地后再播放的. 本文演示如何使用 ...
- SQL 数据库性能优化
http://blog.csdn.net/yzllz001/article/details/54848513 1. 减少数据访问(减少磁盘访问) 2. 返回更少数据(减少网络传输或磁盘访问) 3. ...
- 看似简单!解读C#程序员最易犯的7大错误
编程时犯错是必然的,即使是一个很小的错误也可能会导致昂贵的代价,聪明的人善于从错误中汲取教训,尽量不再重复犯错,在这篇文章中,我将重点介绍C#开发人员最容易犯的7个错误. 格式化字符串 在C#编程中, ...
- SQL Server的复合索引学习【转载】
概要什么是单一索引,什么又是复合索引呢? 何时新建复合索引,复合索引又需要注意些什么呢?本篇文章主要是对网上一些讨论的总结. 一.概念 单一索引是指索引列为一列的情况,即新建索引的语句只实施在一列 ...
- EFCore笔记之异步查询
当在数据库中执行查询时,异步查询可避免阻止线程. 这有助于避免冻结富客户端应用程序的 UI.异步操作还可以增加 Web 应用程序的吞吐量,可以在数据库操作完成时释放线程去处理其他请求. Entity ...
- 谁说NTFS不支持UEFI启动的?启动U盘放不了超过4G的文件怎么办?Server2016 Win10 U盘UEFI启动制作方法
大家都知道,我们平时做启动盘,用得最多的就是UltraISO(软碟通)这个工具了.用它我们可以很简单快速的把一个空白的普通U盘制作成一个PE启动U盘或系统U盘,然后用它来安装系统非常的方便,受到了广大 ...
- hive(I)--学习总结之常用技能
hive是Apache的一个顶级项目,由facebook团队开发,基于java开发面向分析师或BI等人员的数据工具(常用作数据仓库),它将hdfs文件组织成表,使用hive-sql调用mapreduc ...
- 全球NTP服务器列表
全球- pool.ntp.org 欧洲- europe.pool.ntp.org 亚洲- asia.pool.ntp.org 大洋洲- oceania.pool.ntp.org 北美- north-a ...