[Tarjan系列] 无向图e-DCC和v-DCC的缩点
上一篇讲了如何应用Tarjan算法求出e-DCC和v-DCC。
那么这一篇就是e-DCC和v-DCC的应用之一:缩点。
先讲e-DCC的缩点。
我们把每一个e-DCC都看成一个节点,把所有桥边(x,y)看成连接编号为c[x]和c[y]的两个e-DCC间的边,这样我们就会得到一棵树或者森林(原图不连通)。给出缩点的代码,这份代码把e-DCC缩点并把生成的树(森林)储存在另一个邻接表中。
#include<bits/stdc++.h>
#define N 100010
using namespace std;
inline int read(){
int data=,w=;char ch=;
while(ch!='-' && (ch<''||ch>''))ch=getchar();
if(ch=='-')w=-,ch=getchar();
while(ch>='' && ch<='')data=data*+ch-'',ch=getchar();
return data*w;
}
struct Edge{
int nxt,to;
#define nxt(x) e[x].nxt
#define to(x) e[x].to
}e[N<<];
struct EdgeC{
int nxtc,toc;
#define nxtc(x) ec[x].nxtc
#define toc(x) ec[x].toc
}ec[N<<];
int head[N],tot=,n,m,cnt,dfn[N],low[N],c[N],bridge[N],dcc;
int headc[N],totc=;
inline void addedge(int f,int t){
nxt(++tot)=head[f];to(tot)=t;head[f]=tot;
}
inline void addedge_c(int f,int t){
nxtc(++totc)=headc[f];toc(totc)=t;headc[f]=totc;
}
void tarjan(int x,int in_edge){
dfn[x]=low[x]=++cnt;
for(int i=head[x];i;i=nxt(i)){
int y=to(i);
if(!dfn[y]){
tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])
bridge[i]=bridge[i^]=;
}else if(i!=(in_edge^))
low[x]=min(low[x],dfn[y]);
}
}
void dfs(int x){
c[x]=dcc;
for(int i=head[x];i;i=nxt(i)){
int y=to(i);
if(c[y]||bridge[i])continue;
dfs(y);
}
}
int main(){
n=read();m=read();
for(int i=;i<=m;i++){
int x=read(),y=read();
addedge(x,y);addedge(y,x);
}
for(int i=;i<=n;i++)
if(!dfn[i])tarjan(i,);
for(int i=;i<=n;i++){
if(!c[i]){
++dcc;dfs(i);
}
}
for(int i=;i<=tot;i++){
int x=to(i^),y=to(i);
if(c[x]==c[y])continue;
addedge_c(c[x],c[y]);
}
//缩点后的树(森林)的点数为dcc,边数为totc/2
for(int i=;i<totc;i++)
printf("%d %d",toc(i^),toc(i));
return ;
}
v-DCC的缩点由于一个割点可能在很多个v-DCC中而更加麻烦,但是我们也有办法缩。
假设图中有x个割点和y个v-DCC,我们就直接建(x+y)个点的新图。
每一个v-DCC和割点都作为新图的节点存在。建完后我们让每个割点和包含它的v-DCC连边。
给出代码:
#include<bits/stdc++.h>
#define N 100010
using namespace std;
inline int read(){
int data=,w=;char ch=;
while(ch!='-' && (ch<''||ch>''))ch=getchar();
if(ch=='-')w=-,ch=getchar();
while(ch>='' && ch<='')data=data*+ch-'',ch=getchar();
return data*w;
}
struct Edge{
int nxt,to;
#define nxt(x) e[x].nxt
#define to(x) e[x].to
}e[N<<];
struct EdgeC{
int nxtc,toc;
#define nxtc(x) ec[x].nxtc
#define toc(x) ec[x].toc
}ec[N<<];
int head[N],tot=,n,m,rt,dfn[N],low[N],cnt,stk[N],top,num,cut[N];
int headc[N],totc=,new_id[N];
vector<int> dcc[N];
inline void addedge(int f,int t){
nxt(++tot)=head[f];to(tot)=t;head[f]=tot;
}
inline void addedge_c(int f,int t){
nxtc(++totc)=headc[f];toc(totc)=t;headc[f]=totc;
}
void tarjan(int x){
dfn[x]=low[x]=++cnt;
stk[++top]=x;
if(x==rt && head[x]==){
dcc[++num].push_back(x);
return;
}
int flag=;
for(int i=head[x];i;i=nxt(i)){
int y=to(i);
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]){
flag++;
if(x!=rt||flag>)cut[x]=;
num++;int z;
do{
z=stk[top--];
dcc[num].push_back(z);
}while(z!=y);
dcc[num].push_back(x);
}
}else low[x]=min(low[x],dfn[y]);
}
}
int main(){
n=read();m=read();
for(int i=;i<=m;i++){
int x=read(),y=read();
addedge(x,y);addedge(y,x);
}
for(int i=;i<=n;i++)
if(!dfn[i])tarjan(i);
cnt=num;//给每个割点一个新的编号防止重复,从num+1开始
for(int i=;i<=n;i++)
if(cut[i])new_id[i]=++cnt;
for(int i=;i<=cnt;i++){
for(int j=;j<dcc[i].size();j++){
int x=dcc[i][j];
if(cut[x]){//割点和每个v-DCC连边
addedge_c(i,new_id[x]);
addedge_c(new_id[x],i);
}else new_id[x]=i;
}
}
//缩点后的森林(树)点数为cnt,边数为totc/2
for(int i=;i<totc;i+=)
printf("%d %d\n",toc(i^),toc(i));
return ;
}
下一篇更新Tarjan求有向图的SCC以及SCC的缩点
[Tarjan系列] 无向图e-DCC和v-DCC的缩点的更多相关文章
- [Tarjan系列] Tarjan算法求无向图的桥和割点
RobertTarjan真的是一个传说级的大人物. 他发明的LCT,SplayTree这些数据结构真的给我带来了诸多便利,各种动态图论题都可以用LCT解决. 而且,Tarjan并不只发明了LCT,他对 ...
- Tarjan求无向图割点、桥详解
tarjan算法--求无向图的割点和桥 一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不 ...
- 牛客D-Where are you /// kruskal+tarjan找无向图内的环
题目大意: https://ac.nowcoder.com/acm/contest/272/D 在一个无向图中,给定一个起点,从起点开始走遍图中所有点 每条边有边权wi,表示第一次经过该道路时的花费( ...
- 『Tarjan算法 无向图的双联通分量』
无向图的双连通分量 定义:若一张无向连通图不存在割点,则称它为"点双连通图".若一张无向连通图不存在割边,则称它为"边双连通图". 无向图图的极大点双连通子图被 ...
- [Tarjan系列] Tarjan算法求无向图的双连通分量
这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...
- Tarjan系列1
tajan的dfs树系列算法: 求解割点,桥,强连通分量,点双联通分量,边双联通分量: tajan是一个dfs,把一个图变成一个dfs树结构, dfs树结构,本质是通过一个没有任何要求的dfs把图的边 ...
- Tarjan系列算法总结(hdu 1827,4612,4587,4005)
tarjan一直是我看了头大的问题,省选之前还是得好好系统的学习一下.我按照不同的算法在hdu上选题练习了一下,至少还是有了初步的认识.tarjan嘛,就是维护一个dfsnum[]和一个low[],在 ...
- 『Tarjan算法 无向图的割点与割边』
无向图的割点与割边 定义:给定无相连通图\(G=(V,E)\) 若对于\(x \in V\),从图中删去节点\(x\)以及所有与\(x\)关联的边后,\(G\)分裂为两个或以上不连通的子图,则称\(x ...
- tarjan系列算法代码小结
个人使用,可能不是很详细 强联通分量 这里的dfn可以写成low 因为都是在栈中,只要保证该节点的low值不为本身即可 void tarjan(int now) { dfn[now]=low[now] ...
随机推荐
- SpringBoot保存数据报错:could not execute statement; SQL [n/a]; constraint [PRIMARY];nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
使用SpringBoot做JAVA开发时,用Repository.save();保存数据的时候遇到了报错: could not execute statement; SQL [n/a]; constr ...
- windows 10中的ubuntu子系统安装桌面环境的方法
windows 10中的ubuntu子系统安装桌面环境的方法 (How to install Ubuntu-desktop in windows 10 Subsystem for Linux) 转载 ...
- MySQL、sqlalchemy、pymysql、mysqldb、DBAPI之间关系梳理(终于明白了)
MySQL.sqlalchemy.pymysql.mysqldb.DBAPI之间关系梳理(终于明白了) python3不再支持mysqldb 请用pymysql和mysql.connector 问题背 ...
- windows7安装docker异常:looks like something went wrong in step ‘looking for vboxmanage.exe’
一.背景 最近准备抽点时间研究下docker,选择在家中的windows系统上安装. 我的系统是windows7,首先安装Docker Toolbox,Docker Toolbox是一个工具集,主要包 ...
- 【工具】sqlmap 中文手册 使用教程
日期:2019-07-28 09:27:27 更新: 作者:Bay0net 介绍:自己翻译了一下,做个备忘. 0x01. 基本信息 官网 sqlmap: automatic SQL injection ...
- Spring Security(20)——整合Cas
整合Cas 目录 1.1 配置登录认证 1.1.1 配置AuthenticationEntryPoint 1.1.2 配置CasAuthenticationFilt ...
- socket之IO多路复用
概述 目的:同一个线程同时处理多个IO请求. 本文以python的select模块来实现socket编程中一个server同时处理多个client请求的问题. web框架tornado就是以此实现多客 ...
- Hadoop 部署之 Spark (六)
目录 一.Spark 是什么 二.Scala的安装(所有节点) 三.Spark 安装(所有节点) 1.下载安装 2.配置 Spark 环境变量 四.Spark 配置(namenode01) 1.配置 ...
- unity读取灰度图生成等值线图
准备灰度图 grayTest.png,放置于Assets下StreamingAssets文件夹中. 在场景中添加RawImage用于显示最后的等值线图. 生成等值线的过程,使用Marching ...
- Flutter Window环境运行(VSCode + 单独运行Android 虚拟机)
官网以及很多网上文章的开发都是基于Android ,因为它能创建不同类型移动设备虚拟机.但个人始终觉得它太庞大,启动慢耗资源,但我们使用Flutter又离不开虚拟机. 经过实践,现在能成功的单独启动移 ...