连通性问题
求割点
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e4+10;
ll n,m,dfn[N],low[N],tot,root;
bool cut[N];
vector<ll> G[N];
void tarjan(ll u){
dfn[u]=low[u]=++tot;
ll flag=0;
for(auto v:G[u]){
if(!dfn[v]){
tarjan(v),low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
flag++;
if(u!=root||flag>1)cut[u]=true;
}
}else low[u]=min(low[u],dfn[v]);
}
}
int main(){
cin >> n >> m;
for(ll i=1;i<=m;i++){
ll u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
for(ll i=1;i<=n;i++)if(!dfn[i])root=i,tarjan(i);
vector<ll> ans;
for(ll i=1;i<=n;i++)if(cut[i])ans.push_back(i);
cout << ans.size() << endl;
for(auto i:ans)cout << i << ' ';
return 0;
}
求割边
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=150+10,M=5000+10;
vector<ll> G[N],edges;
bool bridge[M*2];
ll n,m,dfn[N],low[N],tot;
void tarjan(ll u,ll in_edge){
dfn[u]=low[u]=++tot;
for(auto e:G[u]){
ll v=edges[e];
if(!dfn[v]){
tarjan(v,e),low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])bridge[e]=bridge[e^1]=true;
}else if(e!=(in_edge^1))low[u]=min(low[u],dfn[v]);
}
}
int main(){
cin >> n >> m;
for(ll i=1;i<=m;i++){
ll u,v;
cin >> u >> v;
edges.push_back(v);
edges.push_back(u);
G[u].push_back(edges.size()-2);
G[v].push_back(edges.size()-1);
}
for(ll i=1;i<=n;i++)if(!dfn[i])tarjan(i,1e18);
vector<pair<ll,ll> > ans;
for(ll i=0;i<edges.size();i+=2)
if(bridge[i])
ans.push_back(make_pair(edges[i],edges[i^1]));
for(auto &i:ans)if(i.first>i.second)swap(i.first,i.second);
sort(ans.begin(),ans.end());
for(auto i:ans)cout << i.first << ' ' << i.second << endl;
return 0;
}
同时求出割点和割边
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=5e5+10,M=2e6+10;
ll n,m,tot,root,dfn[N],low[N];
bool bridge[M*2],cut[N];
vector<ll> G[N],edges;
void tarjan(ll u,ll in_edge){
dfn[u]=low[u]=++tot;
ll flag=0;
for(auto e:G[u]){
ll v=edges[e];
if(!dfn[v]){
tarjan(v,e),low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])bridge[e]=bridge[e^1]=true;
if(low[v]>=dfn[u])if(u!=root||++flag>1)cut[u]=true;
}else if(e!=(in_edge^1))low[u]=min(low[u],dfn[v]);
}
}
int main(){
cin >> n >> m;
for(ll i=1;i<=m;i++){
ll u,v;
cin >> u >> v;
edges.push_back(v);
edges.push_back(u);
G[u].push_back(edges.size()-2);
G[v].push_back(edges.size()-1);
}
for(ll i=1;i<=n;i++)if(!dfn[i])root=i,tarjan(i,1e18);
return 0;
}
求边双连通分量(e-DCC)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=5e5+10,M=2e6+10;
ll n,m,tot,dfn[N],low[N],dcc,c[N];
bool bridge[M*2];
vector<ll> G[N],edges;
vector<ll> ans[N];
void tarjan(ll u,ll in_edge){
dfn[u]=low[u]=++tot;
for(auto e:G[u]){
ll v=edges[e];
if(!dfn[v]){
tarjan(v,e),low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])bridge[e]=bridge[e^1]=true;
}else if(e!=(in_edge^1))low[u]=min(low[u],dfn[v]);
}
}
void dfs(ll u){
c[u]=dcc;
for(auto e:G[u]){
ll v=edges[e];
if(c[v]||bridge[e])continue;
dfs(v);
}
}
int main(){
cin >> n >> m;
for(ll i=1;i<=m;i++){
ll u,v;
cin >> u >> v;
edges.push_back(v);
edges.push_back(u);
G[u].push_back(edges.size()-2);
G[v].push_back(edges.size()-1);
}
for(ll i=1;i<=n;i++)if(!dfn[i])tarjan(i,1e18);
for(ll i=1;i<=n;i++)if(!c[i])++dcc,dfs(i);
for(ll i=1;i<=n;i++)ans[c[i]].push_back(i);
cout << dcc << endl;
for(ll i=1;i<=dcc;i++){
cout << ans[i].size() << ' ';
for(auto j:ans[i])cout << j << ' ';
cout << endl;
}
return 0;
}
求点双连通分量(v-DCC)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=5e5+10;
ll n,m,dfn[N],low[N],tot,root,cnt,sz[N];
bool cut[N];
vector<ll> G[N],dcc[N];
stack<ll> sta;
void tarjan(ll u){
dfn[u]=low[u]=++tot;
sta.push(u);
if(u==root&&sz[u]==0){
dcc[++cnt].push_back(u);
return;
}
ll flag=0;
for(auto v:G[u]){
if(!dfn[v]){
tarjan(v),low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
if(u!=root||++flag>1)cut[u]=true;
cnt++;
ll x;
do{
x=sta.top();
sta.pop();
dcc[cnt].push_back(x);
}while(x!=v);
dcc[cnt].push_back(u);
}
}else low[u]=min(low[u],dfn[v]);
}
}
int main(){
cin >> n >> m;
for(ll i=1;i<=m;i++){
ll u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
if(u!=v)sz[u]++,sz[v]++;
}
for(ll i=1;i<=n;i++)if(!dfn[i])root=i,tarjan(i);
cout << cnt << endl;
for(ll i=1;i<=cnt;i++){
cout << dcc[i].size() << ' ';
sort(dcc[i].begin(),dcc[i].end());
for(auto j:dcc[i]){
cout << j << ' ';
}
cout << endl;
}
return 0;
}