缩点模板

缩点(图的联通)学习笔记

图论的真神——tarjan

其实这个没什么好写的,主要就是缩完点之后树上问题,难点反而是树上的问题。

具体运用——2-sat

强联通缩点,可以类比一个树上的问题?但是有非树边,这里的非树边可以有前向边(就是指向祖先),后向边(指向子孙),横叉边(除了上面的边),很明显后向边对强联通分量是没有影响的,而前项肯定能构造一个强联通,而横叉是根据前向边的情况看是否能构成强联通。可以用 dfnlow 来表示这个点的 dfs序 , low 表示它能到达的 dfs序 最小的一个点。如果这个点的 dfn=low 那么它就不能去到更浅的点了,就相当于一个强联通,直接用一个栈模拟即可。

int dfn[N], low[N], dfncnt, st[N], in_stack[N], top;
int id[N], sc;  // 结点 i 所在 SCC 的编号
vector<int> scc; // SCC i 所拥有的结点
void tarjan(int u) {
    low[u] = dfn[u] = ++dfncnt;//初始化
    st[++top] = u, in_stack[u] = 1;
    for (int i = head[u]; ~i; i = nxt[i]) {
            int v = to[i];
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (in_stack[v]) { //如果在栈里,则继续更新  前向边 和 一部分横叉边
                low[u] = min(low[u], dfn[v]);//此处写dfn[v] 或 low[v]都行
            }
    }
    if (dfn[u] == low[u]) { 
        ++sc;
        int y;
        do{
            y=st[top--],in_stack[y]=0;//出栈
            id[y]=sc,scc[sc].push_back(y);//标记
        }while(y!=u);
    }
}

点双联通和边双联通都是一样的。

边双跟强联通分量缩点很像:

void tarjan(int x,int in_edge){
    dfn[x]=low[x]=++cnt;
    st[++top]=x;
    for(int i=head[x];~i;i=nxt[i]){
	 if(i==(in_edge^1))continue;
        int v=to[i];
        if(!dfn[v]){
            tarjan(v,i);
            low[x]=min(low[x],low[y]);
            if(low[v]>dfn[x])
                bridge[i]=bridge[i^1]=true;
        }
        else low[x]=min(low[x],dfn[v]);
    }
    if(dfn[x]==low[x]){
        ++dcc_cnt;
        int y;
        do{
            y=st[top--],dcc[x]=dcc_cnt;
        }while(y!=x);
    }
}

点双:

void tarjan(int u,int ID) {
	vis[u]=1;
	low[u]=dfn[u]=++cnt;
	st[++top]=u;
	if(rt==u && !e[u].size()) {
		g[++sc].push_back(u);
		return ;
	}
	int flag=0;
	for(auto tmp:e[u]) {
		int v=tmp.first,id=tmp.second;
		//if((id^1) ==(ID^1))continue;
		if(!dfn[v]) {
			tarjan(v,id);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]) {
				++flag;
				++sc;
				int y;
				do {
					y=st[top--];
					id[y]=sc;
					h[sc].push_back(y);
				} while(y!=v);
				id[u]=u;
			}
		} else low[u]=min(low[u],dfn[v]);
	}
}
posted @ 2025-03-02 21:15  hnczy  阅读(2)  评论(0编辑  收藏  举报