[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] ...
随机推荐
- Golang 二维切片初始化
package main import "fmt" func main() { // 方法0 row, column := 3, 4 var answer [][]int for ...
- IdentityServer4入门一
这几天学习IdentityServer4,感觉内容有点乱,也可能自己水平有限吧.但为了巩固学习的内容,也打算自己理一下思路. 首先IdentityServer解决什么问题? 下图是我们的一个程序的组织 ...
- EntityFramework Core Code First 已有数据库
问题场景:我已经有一个数据库,想用 EF core Code First,怎么办? 首先,可以参考微软的API文档:通过现有数据库在 ASP.NET Core 上开始使用 EF Core, 这一步可以 ...
- PHP多进程开发与Redis结合实践
原文:https://blog.51cto.com/laok8/2107892?source=drh 业务逻辑介绍: 用户在 APP 上发帖子,然后存储到 Redis 的 List 列表中 利用 Li ...
- /proc/sys/kernel/sysrq /proc/sysrq-trigger----强制重启/触发器
LINUX远程强制重启/proc/sys/kernel/sysrq /proc/sysrq-trigger----触发器 ttp://blog.csdn.net/beckdon/article/det ...
- Flask中路由参数
Flask中路由参数.请求方式设置 一.参数设置 1.参数类型 Flask中参数的使用 @app.route('/parames/<username>/') def hello_world ...
- oracle相关知识点
oracle数据库,实例名和数据库是一一对应的,oracle服务端可以启动多个实例,对应于多个数据库. 数据库可以通过sqlplus / as sysdba 进入默认SID的实例, 查看当前的实例名: ...
- python3 @classmethod 和 @staticmethod 的区别
如果您将某个东西定义为classmethod,这可能是因为您打算从类而不是类实例中调用它. 定义类方法的几种方式: 常规方式 : 需要self隐士传递当前类 ...
- html+大文件上传
前言:因自己负责的项目(jetty内嵌启动的SpringMvc)中需要实现文件上传,而自己对java文件上传这一块未接触过,且对 Http 协议较模糊,故这次采用渐进的方式来学习文件上传的原理与实践. ...
- 机器阅读理解综述Neural Machine Reading Comprehension Methods and Trends(略读笔记)
标题:Neural Machine Reading Comprehension: Methods and Trends 作者:Shanshan Liu, Xin Zhang, Sheng Zhang, ...