边双连通分量还有桥

我发现了两种边双的写法

1.先求桥,标记桥再dfs求连通块,< 似乎有点麻烦

2.直接上有向图的写法,把回头的情况标记一下

其1

int tarjan(int x, int fa) {
	low[x] = dfn[x] = ++df;

	for (int i = head[x]; i; i = G[i].next) {
		int p = G[i].to;
		if (!dfn[p]) {
			tarjan(p, i);

			low[x] = min(low[x], low[p]);
			if (low[p] > dfn[x]) {
				aaa++;
				bri[i] = bri[i ^ 1] = 1;
			}
		}
		else if (fa == -1 || i != (fa ^ 1)) {
			low[x] = min(low[x], dfn[p]);
		}
	}
	return 0;
}

int dfss(int x) {
	clor[x] = ans;
	for (int i = head[x]; i; i = G[i].next) {
		int p = G[i].to;
		if (clor[p] || bri[i]) continue;
		dfss(p);
	}
	return 0;
}




/////
scanf("%d %lld", &n, &m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &be, &en);
		insert(be, en);
		insert(en, be);
	}
	tarjan(1, -1);
	for (int i = 1; i <= n; i++) {
		if (!clor[i]) {
			ans++;
			dfss(i);
		}
	}

ans 就是边双分量

其2.

int low[maxn], dfn[maxn], df, ans;
int clor[maxn];
void insert(int be, int en) {
    G[be].push_back(en);
}
  
int tarjan(int x,int fa) {
    low[x] = dfn[x] = ++df;
    s.push(x);
    int flag=0;
    for (int i = 0; i < G[x].size(); i++) {
        int p = G[x][i];
        if (p == fa){
            flag++;
            if(flag == 1) continue;//和昆哥学的,标记回头,预防重边
        }
        if (!dfn[p]) {
            tarjan(p, x);
            low[x] = min(low[x], low[p]);
        }
        else if (!clor[p]) {
            low[x] = min(dfn[p], low[x]);
        }
    }
    if (dfn[x] == low[x]) {
        ans++;
        while (1) {
            int a = s.top();
            clor[a] = ans;
            s.pop();
            if (a == x) break;
        }
    }
    return 0;
}



  ////

  

猜你喜欢

转载自www.cnblogs.com/lesning/p/12111555.html
今日推荐