強連通分量#
染色為搜索樹根節點編號:
void tarjan (int p) {
dfn[p] = low[p] = ++tim;
v[p] = 1;
s.push(p);
for (int i = head[p]; i; i = e[i].nex) {
int y = e[i].to;
if (!dfn[y]) {
tarjan(y);
low[p] = min(low[p], low[y]);
}
else if(v[y]){
low[p] = min(low[p], dfn[y]);
}
}
if (dfn[p] == low[p]) {
color[p] = p;
v[p] = 0;
while (s.top() != p) {
color[s.top()] = p;
v[s.top()] = 0;
s.pop();
}
s.pop();
}
}
縮點#
沒有板子。。。
情況很多。有時可以只統計出入度
有時可以建新圖 (namespace namespace namespace)
割點#
void tarjan (int p){
dfn[p] = low[p] = ++tim;
int kidsCnt = 0;
for (int i = head[p]; i; i = e[i].nex) {
int y = e[i].to;
if (!dfn[y]) {
++kidsCnt;
tarjan(y);
low[p] = min(low[p], low[y]);
if ((p == root && kidsCnt >= 2) || (p != root && dfn[p] <= low[y])) {
cut[p] = 1;
//++cutsCnt;會重複統計數量
}
}
else {
low[p] = min(low[p], dfn[y]);
}
}
}
調用:
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) {
root = i;
tarjan(i);
}
}
點雙連通分量#
沒有模板題我也不知道對沒對。。。
void tarjan (int p, int fa) {
dfn[p] = low[p] = ++tim;
for (int i = head[p]; i; i = e[i].nex) {
int y = e[i].to;
if (!dfn[y]) {
st[++top] = y;
tarjan(y, p);
low[p] = min(low[p], low[y]);
if (low[y] >= dfn[u]) {
++cnt;
while (st[top] != y) {
bcc[cnt].push_back(st[top--]);
}
bcc[cnt].push_back(stack[top--]);
bcc[cnt].push_back(p);
}
}
else if (y != fa) {
low[p] = min(low[p], dfn[y]);
}
}
}
割邊 (橋)#
newp
的初值要設為1
void tarjan (int p, int ed) {//ed為來的邊
dfn[p] = low[p] = ++tim;
for (int i = head[p]; i; i = e[i].nex) {
int y = e[i].to;
if (!dfn[y]) {
tarjan(y, i);
low[p] = min(low[p], low[y]);
if (dfn[p] < low[y]) {
bridge[i] = bridge[i ^ 1] = 1;
}
}
else if (i != (ed ^ 1)) {
low[p] = min(low[p], dfn[y]);
}
}
}
邊雙連通分量#
先來一遍割邊的tarjan
然後有個dfs
void dfs (int p) {
dcolor[p] = dcnt;
for (int i = head[p]; i; i = e[i].nex) {
int y = e[i].to;
if (dcolor[y] != 0 || bridge[i] == 1) {
continue;
}
dfs(y);
}
}
這個dfs
要這樣用
for (int i = 1; i <= n; ++i) {
if (!dcolor[i]) {
++dcnt;
dfs(i);
}
}
聯通圖變成邊雙連通圖要加的邊數#
for (int i = 1; i <= m; ++i) {
if (dcolor[e[i * 2].frm] != dcolor[e[i * 2].to]) {
++out[dcolor[e[i * 2].frm]];
++out[dcolor[e[i * 2].to]];
}
}
int leaf = 0;
for (int i = 1; i <= dcnt; ++i) {
if (out[i] == 1) {
++leaf;
}
}
printf("%d\n", leaf == 1 ? 0 : (leaf + 1) / 2);