Tarjan 算法应用标程

模拟赛不会写点双开了挂,现在复习一下

Tarjan 算法应用标程

变量解释:

名称 用途 类型
\(dfn\) 时间戳 int[]
\(low\) 回溯最早时间戳 int[]
\(child\) 孩子数 int[]
\(ti\) 时间 int
\(s\) 源点 int
\(nme\) 所属连通分量 int[]
\(cut\) 是否是割 bool[]
\(cnt\) 连通分量数 int
\(d(s)cc\) 连通分量所含点 vector<int>[]
\(ins\) 是否在栈中 bool[]
\(tp\) 栈顶 int
\(x\) 栈顶元素 int

割边与边双连通分量(\(e-dcc\)

//割边
void Tarjan(int u,int e){
	low[u] = dfn[u] = ++ti;
	for(int i = head[u];~i;i = edge[i].nxt){
    //链式前向星存图, 终点指向 -1
		int v = edge[i].to;
		if(!dfn[v]){
			Tarjan(v,i);
			low[u] = min(low[u],low[v]);
			if(low[v] > dfn[u])
				cut[i] = cut[i ^ 1] = 1;
		}
		else if(i != (e ^ 1))
        //各条边的名字从 0 开始,
        //使 0 与 1 配对,2 与 3 配对……
			low[u] = min(low[u],dfn[v]);
	}
}
void DFS(int u){//加上就是边双缩点
	dcc[cnt].push_back(u);//cnt 在主函数累加
	nme[u] = cnt;
	for(int i = head[u];~i;i = edge[i].nxt){
		int v = edge[i].to;
		if(cut[i]) continue;
		DFS(v);
	}
}

割点与点双连通分量(\(v-ecc\)

//割点
void Tarjan(int u){
	low[u] = dfn[u] = ++ti;
	int child = 0;
	for(int i = head[u];~i;i = edge[i].nxt){
		int v = edge[i].to;
		if(!dfn[v]) {
			Tarjan(v); 
			low[u] = min(low[u],low[v]);
            if(low[v] >= dfn[u]){
                child++;
                if(u != s || child >= 2)
                //源点在主函数遍历
					cut[u] = true;
            }
		}
		else low[u] = min(low[u],dfn[v]);
	}
}
//点双
void Tarjan(int u){
	dfn[u] = low[u] = ++ti;
	st[++tp] = u;
  	if(u == s && head[u] == -1){
    	dcc[++cnt].push_back(u);
    	return;
  	}
  	int child = 0;
	for(int i = head[u];~i;i = edge[i].nxt){
		int v = edge[i].to;
		if(!dfn[v]){
			Tarjan(v);
			low[u] = min(low[u],low[v]);
			if(low[v] >= dfn[u]){
        		child++;
        		if(u != s || child > 1) cut[u] = 1;
        		cnt++; int x;
        		do{
          			x = st[tp--];
         			dcc[cnt].push_back(x);
        		} while(x != v);
        		dcc[cnt].push_back(u);
			}
		}
        else low[u] = min(low[u],dfn[v]);
	}
}

强连通分量(\(scc\)

//强
void Tarjan(int u){
	dfn[u] = low[u] = ++ti;
	ins[u] = 1; st[++tp] = u;
	for(int i = head[u];~i;i = edge[i].nxt){
		int v = edge[i].to;
		if(!dfn[v]){
			Tarjan(v);
			low[u] = min(low[u],low[v]);
		}
		else if(ins[v])
			low[u] = min(low[u],dfn[v]);
	}
	if(dfn[u] == low[u]){
		++cnt; int x;
		do{
			x = st[tp--]; ins[x] = 0;
			nme[x] = scc; scc[cnt].insert(x);
		} while(x != u);
	}
}
posted @ 2023-11-11 23:40  CultReborn  阅读(20)  评论(0)    收藏  举报