点双连通
poj1523
题意
- 给出无向图,求割点,并给出每个割点去掉后会形成几个分量
思路
代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <cstddef>
const int N = 1005;
std::vector<int> g[N];
int n, son[N], low[N], num[N], id, root;
bool flag[N];
void init() {
std::memset(son, 0, sizeof(son));
std::memset(low, 0, sizeof(low));
std::memset(num, 0, sizeof(num));
std::memset(flag, false, sizeof(flag));
id = 0;
n = 0;
for(int i = 1; i < N; ++ i) g[i].clear();
}
void dfs(int u, int fu) {
num[u] = low[u] = ++ id;
for(unsigned int i = 0; i < g[u].size(); ++ i) {
int v = g[u][i];
if(!num[v]) {
dfs(v, u);
low[u] = std::min(low[u], low[v]);
if(low[v] >= num[u] && u != root) {
++ son[u];
flag[u] = true;
}
} else if(num[v] < num[u] && v != fu) {
low[u] = std::min(low[u], num[v]);
}
}
if(son[u] >= 2 && u == root) {
flag[u] = true;
}
return;
}
int main() {
int u, v, idx = 0;
while(scanf("%d", &u) && u) {
scanf("%d", &v);
init();
n = std::max(u, n);
n = std::max(v, n);
g[u].push_back(v);
g[v].push_back(u);
while(scanf("%d", &u) && u) {
scanf("%d", &v);
n = std::max(u, n);
n = std::max(v, n);
g[u].push_back(v);
g[v].push_back(u);
}
root = n;
dfs(n, n);
bool exist = false;
if(idx >= 1) printf("\n");
printf("Network #%d\n", ++ idx);
for(int i = 1; i <= n; ++ i) {
if(flag[i]) {
exist = true;
if(i != root) {
printf(" SPF node %d leaves %d subnets\n", i, son[i] + 1);
} else if(i == root) {
printf(" SPF node %d leaves %d subnets\n", i, son[i]);
}
}
}
if(!exist) printf(" No SPF nodes\n");
}
return 0;
}
边双连通
poj3352
题意
思路
tarjan
更新low[]
数组之后,再缩点
- 缩点之后统计叶子节点,需要加的边的条数等于
(叶子节点数 + 1)/ 2
代码
#include <iostream>
#include <cstring>
#include <process.h>
#include <string>
#include <algorithm>
#include <vector>
const int N = 1005;
int n, m, id, low[N], degree[N];
std::vector<int> g[N];
void init() {
for (int i = 0; i <= n; ++ i) g[i].clear();
id = 0;
std::memset(low, 0, sizeof(low));
std::memset(degree, 0, sizeof(degree));
}
void dfs(int u, int fu) {
low[u] = ++ id;
for (unsigned int i = 0; i < g[u].size(); ++ i) {
int v = g[u][i];
if(v == fu) continue;
if(!low[v]) dfs(v, u);
low[u] = std::min(low[u], low[v]);
}
}
void tarjan() {
int cnt = 0;
for (int i = 1; i <= n; ++ i) {
for(unsigned int j = 0; j < g[i].size(); ++ j) {
if(low[i] != low[g[i][j]]) ++ degree[low[i]];
}
}
for (int i = 1; i <= n; ++ i) {
if(degree[i] == 1) ++ cnt;
}
printf("%d\n", (cnt + 1) / 2);
}
int main() {
while (scanf("%d %d", &n, &m) != EOF) {
init();
for (int i = 1; i <= m; ++ i) {
int u, v;
scanf("%d %d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 1);
tarjan();
}
system("pause");
return 0;
}