连通分量

无向图

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);
    
    // printf ("%d\n", scc_cnt);
    
    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++;
        }
    }
    
    // printf ("start = %d, end = %d\n", Start_cnt, End_cnt);
    
    if (scc_cnt == 1) {
        printf ("0");
    }
    else {
        printf ("%d", Max (Start_cnt, End_cnt));
    }
	return 0;
}
posted @ 2021-04-10 15:03  C2022lihan  阅读(101)  评论(0编辑  收藏  举报