图的联通

求无向图割点,割边,双连通分量;求有向图强连通分量,缩点。

强联通分量


#include<bits/stdc++.h>
#define MN 4000010
#define pb push_back

using namespace std;

int n, m, vis[MN], stk[MN], top, cnt;
int dfn[MN], low[MN], bel[MN], tc;
int a[MN], sp[MN], f[MN], in[MN], ans;
int hd[MN], to[MN], nxt[MN], tot=1;
vector<int> ee[MN]; queue<int> q;

void eadd(int u,int v) {
	to[++tot]=v;
	nxt[tot]=hd[u];
	hd[u]=tot;
}

void tarjan(int x) {
	low[x]=dfn[x]=++tc;
	vis[x]=1, stk[++top]=x;
	for(int i=hd[x]; i; i=nxt[i]) {
		int y=to[i];
		if(vis[y]==2) continue;
		if(!vis[y]) tarjan(y);
		low[x]=min(low[x],low[y]);
	}
	if(dfn[x]==low[x]) {
		int p; cnt++;
		while(stk[top+1]!=x) {
			p=stk[top--];
			vis[p]=2, bel[p]=cnt;
		}
	}
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    for(int i=1; i<=n; ++i)
    	cin >> a[i];
	while(m--) {
		int u, v, w;
		cin >> u >> v;
		eadd(u,v);
	}
	for(int i=1; i<=n; ++i)
		if(!dfn[i]) tarjan(i);
    return 0;
}



割点

判断法则(?

  • 根,至少两个子树

  • 非根,存在 \(dfn_x\leq low_y\)

感性理解一下(雾。

#include<bits/stdc++.h>
#define MN 100010
#define pb push_back

using namespace std;

int n, m, tc, buc[MN], rt;
int dfn[MN], low[MN], cnt;
vector<int> to[MN];

void tarjan(int x) {
	dfn[x]=low[x]=++tc;
	int son=0;
	for(int i=0; i<to[x].size(); ++i) {
		int y=to[x][i];
		if(dfn[y]) low[x]=min(low[x],dfn[y]);
		else {
			son++, tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x]&&x!=rt)
				cnt+=(!buc[x]), buc[x]=1; 
		}
	}
	if(son>=2&&x==rt) cnt+=(!buc[x]), buc[x]=1;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
	while(m--) {
		int u, v;
		cin >> u >> v;
		to[u].pb(v);
		to[v].pb(u);
	}
	for(int i=1; i<=n; ++i)
		if(!dfn[i]) rt=i, tarjan(i);
	cout << cnt << endl;
	for(int i=1; i<=n; ++i)
		if(buc[i]) cout << i << " ";
    return 0;
}

如果是割边把等号去掉。


点双联通

求的时候往 stack 里塞,注意判断单独一个点。

#include<bits/stdc++.h>
#define MN 4000010
#define pb push_back

using namespace std;

int n, m, tc, stk[MN], top;
int dfn[MN], low[MN], cnt, rt;
int hd[MN], to[MN], nxt[MN], tot;
vector<int> bcc[MN];

void eadd(int u,int v) {
	to[++tot]=v;
	nxt[tot]=hd[u];
	hd[u]=tot;
}

void tarjan(int x) {
	dfn[x]=low[x]=++tc;
	stk[++top]=x;
	int son=0;
	for(int i=hd[x]; i; i=nxt[i]) {
		int y=to[i];
		if(dfn[y]) low[x]=min(low[x],dfn[y]);
		else {
			son++, tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x]) {
				bcc[++cnt].pb(x);
				while(stk[top+1]!=y) bcc[cnt].pb(stk[top--]);
			}
		}
	}
	if(son==0&&x==rt) bcc[++cnt].pb(x);
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
	while(m--) {
		int u, v;
		cin >> u >> v;
		eadd(u,v);
		eadd(v,u);
	}
	for(int i=1; i<=n; ++i)
		if(!dfn[i]) rt=i, tarjan(i);
	cout << cnt << endl;
	for(int i=1; i<=cnt; ++i) {
		cout << bcc[i].size() << " ";
		for(int j=0; j<bcc[i].size(); ++j)
			cout << bcc[i][j] << " ";
		cout << endl;
	}
    return 0;
}


边双联通

把割边去掉然后 dfs 就好了 qwq

#include<bits/stdc++.h>
#define MN 4000010
#define pb push_back

using namespace std;

int n, m, vis[MN], is[MN], tc;
int dfn[MN], low[MN], cnt;
int hd[MN], to[MN], nxt[MN], tot=1;
vector<int> bcc[MN];

void eadd(int u,int v) {
	to[++tot]=v;
	nxt[tot]=hd[u];
	hd[u]=tot;
}

void tarjan(int x,int fa) {
	dfn[x]=low[x]=++tc;
	int son=0;
	for(int i=hd[x]; i; i=nxt[i]) {
		int y=to[i];
		if(y==fa) continue;
		if(dfn[y]) low[x]=min(low[x],dfn[y]);
		else {
			son++, tarjan(y,x);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x]) is[i]=is[i^1]=1;
		}
	}
}

void dfs(int p) {
	bcc[cnt].pb(p);
	for(int i=hd[p]; i; i=nxt[i]) {
		int y=to[i];
		if(vis[y]||is[i]) continue;
		vis[y]=1, dfs(y);
	}
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
	while(m--) {
		int u, v;
		cin >> u >> v;
		eadd(u,v);
		eadd(v,u);
	}
	for(int i=1; i<=n; ++i)
		if(!dfn[i]) tarjan(i,0);
	for(int i=1; i<=n; ++i)
		if(!vis[i]) vis[i]=1, cnt++, dfs(i);
	cout << cnt << endl;
	for(int i=1; i<=cnt; ++i) {
		cout << bcc[i].size() << " ";
		for(int j=0; j<bcc[i].size(); ++j)
			cout << bcc[i][j] << " ";
		cout << endl;
	}
    return 0;
}
posted @ 2023-08-12 22:56  Hypoxia571  阅读(3)  评论(0编辑  收藏  举报