无向图
1.求无向图的边双连通分量
int dfn[Maxn + 5], low[Maxn + 5], timestamp;
int id[Maxn + 5], dcc_cnt;
int st[Maxn + 5], Top;
bool is_bridge[Maxm * 2 + 5];
void Tarjan (int u, int fa) {
dfn[u] = low[u] = ++timestamp;
st[++Top] = u;
for (int i = Head[u]; i; i = e[i].Next) {
int v = e[i].to;
if (dfn[v] == 0) {
Tarjan (v, i);
low[u] = Min (low[u], low[v]);
if (low[v] > dfn[u]) {
is_bridge[i] = is_bridge[i ^ 1] = 1;
}
}
else if (fa != (i ^ 1)) {
low[u] = Min (low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
dcc_cnt++;
int v;
do {
v = st[Top--];
id[v] = dcc_cnt;
}while (u != v);
}
}
2.求无向图的点双连通分量
int dfn[Maxn + 5], low[Maxn + 5], timestamp;
int Top, dcc_cnt;
pair <int, int> st[Maxm + 5];
vector <pair <int, int> > block[Maxm + 5];
void Tarjan (int u, int fa) {
dfn[u] = low[u] = ++timestamp;
for (int i = Head[u]; i; i = e[i].Next) {
int v = e[i].to;
if (dfn[v] == 0) {
st[++Top] = make_pair (u, v);
Tarjan (v, u);
low[u] = Min (low[u], low[v]);
if (low[v] >= dfn[u]) {
dcc_cnt++;
pair <int, int> tem;
do {
tem = st[Top--];
block[dcc_cnt].push_back (make_pair (Min (tem.first, tem.second), Max (tem.first, tem.second)));
}while (tem != make_pair (u, v));
}
}
else if (v != fa) {
if (dfn[v] <= dfn[u])
st[++Top] = make_pair (u, v);
low[u] = Min (low[u], dfn[v]);
}
}
}
3.求要加哪些边才能使原图成为边双连通
#include <map>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
template <typename T> int read (T &x) {x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return 1;}
template <typename T> void write (T x) {if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 2500;
const int Maxm = 2 * 1e4;
int n, m;
int len = 1, Head[Maxn + 5], len_dcc = 1, Head_dcc[Maxn + 5];
struct edge {
int to, Next;
}e[Maxm * 2 + 5], e_dcc[Maxm * 2 + 5];
void add (int x, int y) {
e[++len].to = y;
e[len].Next = Head[x];
Head[x] = len;
}
void add_dcc (int x, int y) {
e_dcc[++len_dcc].to = y;
e_dcc[len_dcc].Next = Head_dcc[x];
Head_dcc[x] = len_dcc;
}
int dfn[Maxn + 5], low[Maxn + 5], timstamp;
int st[Maxn + 5], Top;
int id[Maxn + 5], _min[Maxn + 5], dcc_cnt;
bool is_bridge[Maxm * 2 + 5];
void Tarjan (int u, int fa) {
dfn[u] = low[u] = ++timstamp;
st[++Top] = u;
for (int i = Head[u]; i; i = e[i].Next) {
int v = e[i].to;
if (dfn[v] == 0) {
Tarjan (v, i);
low[u] = Min (low[u], low[v]);
if (low[v] > dfn[u])
is_bridge[i] = is_bridge[i ^ 1] = 1;
}
else if ((i ^ 1) != fa)
low[u] = Min (low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
dcc_cnt++;
int v;
do {
v = st[Top--];
id[v] = dcc_cnt;
_min[dcc_cnt] = Min (_min[dcc_cnt], v);
}while (u != v);
}
}
int d[Maxn + 5];
vector <pair <int, int> > v;
void dfs (int u, int fa) {
dfn[u] = ++timstamp;
if (d[u] == 1) {
v.push_back (make_pair (dfn[u], _min[u]));
}
for (int i = Head_dcc[u]; i; i = e_dcc[i].Next) {
int v = e_dcc[i].to;
if (v == fa) continue;
dfs (v, u);
}
}
int g[Maxn + 5][Maxn + 5];
signed main () {
memset (_min, 0x3f, sizeof _min);
read (n); read (m);
for (int i = 1; i <= m; i++) {
int x, y; read (x); read (y);
add (x, y); add (y, x);
}
for (int i = 1; i <= n; i++) {
if (dfn[i] == 0)
Tarjan (i, -1);
}
for (int i = 2; i <= len; i++)
if (is_bridge[i] == 1)
d[id[e[i].to]]++;
for (int u = 1; u <= n; u++) {
for (int i = Head[u]; i; i = e[i].Next) {
int v = e[i].to;
if (id[u] == id[v]) continue;
if (is_bridge[i] == 1) {
if (g[id[u]][id[v]] || g[id[v]][id[u]]) continue;
g[id[u]][id[v]] = g[id[v]][id[u]] = 1;
add_dcc (id[u], id[v]); add_dcc (id[v], id[u]);
}
}
}
int root;
for (int i = 1; i <= dcc_cnt; i++) {
if (d[i] > 1) {
timstamp = 0;
dfs (i, -1);
root = i;
break;
}
}
sort (v.begin (), v.end ());
int len = (int)v.size ();
printf ("%d\n", (len + 1) >> 1);
for (int i = 0, j = (len + 1 >> 1); i <= len / 2, j < len; i++, j++) {
printf ("%d %d\n", v[i].second, v[j].second);
}
if (len & 1) printf ("%d %d", v[len / 2].second, root);
return 0;
}
4.求要加多少点才能使原图成为边双连通
#include <map>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
template <typename T> int read (T &x) {x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return 1;}
template <typename T> void write (T x) {if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 2500;
const int Maxm = 2 * 1e4;
int n, m;
int len = 1, Head[Maxn + 5], len_dcc = 1, Head_dcc[Maxn + 5];
struct edge {
int to, Next;
}e[Maxm * 2 + 5], e_dcc[Maxm * 2 + 5];
void add (int x, int y) {
e[++len].to = y;
e[len].Next = Head[x];
Head[x] = len;
}
void add_dcc (int x, int y) {
e_dcc[++len_dcc].to = y;
e_dcc[len_dcc].Next = Head_dcc[x];
Head_dcc[x] = len_dcc;
}
int dfn[Maxn + 5], low[Maxn + 5], timstamp;
int st[Maxn + 5], Top;
int id[Maxn + 5], _min[Maxn + 5], dcc_cnt;
bool is_bridge[Maxm * 2 + 5];
void Tarjan (int u, int fa) {
dfn[u] = low[u] = ++timstamp;
st[++Top] = u;
for (int i = Head[u]; i; i = e[i].Next) {
int v = e[i].to;
if (dfn[v] == 0) {
Tarjan (v, i);
low[u] = Min (low[u], low[v]);
if (low[v] > dfn[u])
is_bridge[i] = is_bridge[i ^ 1] = 1;
}
else if ((i ^ 1) != fa)
low[u] = Min (low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
dcc_cnt++;
int v;
do {
v = st[Top--];
id[v] = dcc_cnt;
_min[dcc_cnt] = Min (_min[dcc_cnt], v);
}while (u != v);
}
}
int d[Maxn + 5];
vector <pair <int, int> > v;
void dfs (int u, int fa) {
dfn[u] = ++timstamp;
if (d[u] == 1) {
v.push_back (make_pair (dfn[u], _min[u]));
}
for (int i = Head_dcc[u]; i; i = e_dcc[i].Next) {
int v = e_dcc[i].to;
if (v == fa) continue;
dfs (v, u);
}
}
int g[Maxn + 5][Maxn + 5];
signed main () {
memset (_min, 0x3f, sizeof _min);
read (n); read (m);
for (int i = 1; i <= m; i++) {
int x, y; read (x); read (y);
add (x, y); add (y, x);
}
for (int i = 1; i <= n; i++) {
if (dfn[i] == 0)
Tarjan (i, -1);
}
for (int i = 2; i <= len; i++)
if (is_bridge[i] == 1)
d[id[e[i].to]]++;
for (int u = 1; u <= n; u++) {
for (int i = Head[u]; i; i = e[i].Next) {
int v = e[i].to;
if (id[u] == id[v]) continue;
if (is_bridge[i] == 1) {
if (g[id[u]][id[v]] || g[id[v]][id[u]]) continue;
g[id[u]][id[v]] = g[id[v]][id[u]] = 1;
add_dcc (id[u], id[v]); add_dcc (id[v], id[u]);
}
}
}
int root;
for (int i = 1; i <= dcc_cnt; i++) {
if (d[i] > 1) {
timstamp = 0;
dfs (i, -1);
root = i;
break;
}
}
sort (v.begin (), v.end ());
int len = (int)v.size ();
printf ("%d\n", (len + 1) >> 1);
for (int i = 0, j = (len + 1 >> 1); i <= len / 2, j < len; i++, j++) {
printf ("%d %d\n", v[i].second, v[j].second);
}
if (len & 1) printf ("%d %d", v[len / 2].second, root);
return 0;
}
5.求要加多少边才能使原图成为点双连通(还不会)
2.有向图
1.求有向图的强连通分量
vector <int> g[Maxn + 5];
int dfn[Maxn + 5], low[Maxn + 5], timestamp;
int scc_cnt, id[Maxn + 5];
int Top, st[Maxn + 5];
bool in_st[Maxn + 5];
void Tarjan (int u) {
dfn[u] = low[u] = ++timestamp;
st[++Top] = u; in_st[u] = 1;
for (int i = Head[u]; i; i = e[i].Next) {
int v = e[i].to;
if (dfn[v] == 0) {
Tarjan (v);
low[u] = Min (low[u], low[v]);
}
else if (in_st[v] == 1)
low[u] = Min (low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
scc_cnt++;
int v;
do {
v = st[Top--];
id[v] = scc_cnt;
g[scc_cnt].push_back (v);
in_st[v] = 0;
}while (v != u);
}
}
4.求要加多少边才能使原图成为强连通
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define ULL unsigned long long
using namespace std;
template <typename T> int read (T &x) {x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return 1;}
template <typename T> void write (T x) {if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 100;
const int Maxm = 1e4;
int n;
int dfn[Maxn + 5], low[Maxn + 5], timestamp;
int st[Maxn + 5], Top;
bool in_st[Maxn + 5];
int scc_cnt, Size[Maxn + 5], id[Maxn + 5];
int din[Maxn + 5], dout[Maxn + 5];
int len, head[Maxn + 5];
struct edge {
int to, next;
}e[Maxm + 5];
void add (int x, int y) {
e[++len].to = y;
e[len].next = head[x];
head[x] = len;
}
void Tarjan (int u) {
dfn[u] = low[u] = ++timestamp;
st[++Top] = u; in_st[u] = 1;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (dfn[v] == 0) {
Tarjan (v);
low[u] = Min (low[u], low[v]);
}
else if (in_st[v] == 1) {
low[u] = Min (low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
scc_cnt++;
int v;
do {
v = st[Top--];
in_st[v] = 0;
id[v] = scc_cnt;
Size[scc_cnt]++;
}while (u != v);
}
}
int main () {
read (n);
for (int i = 1; i <= n; i++) {
int x; read (x);
while (x != 0) {
add (i, x);
read (x);
}
}
for (int i = 1; i <= n; i++)
if (dfn[i] == 0)
Tarjan (i);
int Start_cnt = 0, End_cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = head[i]; j; j = e[j].next) {
int k = e[j].to;
int u = id[i], v = id[k];
if (u == v) continue;
dout[u]++;
din[v]++;
}
}
for (int i = 1; i <= scc_cnt; i++) {
if (din[i] == 0) {
Start_cnt++;
}
if (dout[i] == 0) {
End_cnt++;
}
}
if (scc_cnt == 1) {
printf ("0");
}
else {
printf ("%d", Max (Start_cnt, End_cnt));
}
return 0;
}