[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] ...
随机推荐
- 【面试题总结】1、统计字符串中某个字符出现的次数(2-Python实现)
1.可以使用Python的字典实现,对于一个特定的字符串,使用for循环遍历其中的字符,并保存成字典形式.字典的key为字符,value为字符在整个字符串中出现的次数. 2.拓展:如果题目为比较两个字 ...
- 浅述不同版本ios系统有什么特点 ios 1 -ios 12
版本记录 版本号 时间 V2.0 2019.08.20 前言 到目前为止,ios的版本已经发到了ios11的测试版,今年正式版马上就会出来,ios发布了这么多的版本,到底每个版本都有什么显著的特点?用 ...
- HearthBuddy 召唤随从的问题
代码如下,在SilverFish\SilverFish\ai\Playfield.cs文件中 public void callKid(CardDB.Card c, int zonepos, bool ...
- HearthBuddy Ai调试实战1-->出牌的时候,少召唤了图腾就结束回合
期望通过ai的调试,来搞明白出牌的逻辑. 55是投火无面者63是恐狼前锋34是风怒36是自动漩涡打击装置13是空灵召唤者, "LocStringZhCn": "<b ...
- apt如何列出所有已经安装的软件包
apt如何列出所有已经安装的软件包 转 https://www.helplib.com/ubuntu/article_155294 问题: 我想将所有已安装软件包的列表输出到文本文件中,以便我可以查看 ...
- (翻译) How variables are allocated memory in Javascript? | scope chain | lexicial scope
总结: 阅读下面文章需要15分钟 提问者的问题是JavaScript中内存是怎么分配的,在介绍的过程作者涉及计到了JS中 Scope Chain和调用函数call生成lexicial environm ...
- using代码性能影响?
Q:using当作命名空间?A:对代码编译有影响,对代码执行无任何影响:https://www.cnblogs.com/Interkey/p/UsingNameSpace.html Q:using用来 ...
- dbtreeview
http://www.delphipages.com/comp/dynamic_dbtreeview-6302.html https://files.cnblogs.com/files/jijm123 ...
- mysql允许远程机器连接
mysql> use mysql; Reading table information for completion of table and column names You can turn ...
- webdriervAPI基础元素定位
from selenium import webdriver driver = webdriver.Chorme() driver.get("http://www.baidu.co ...