题目
题目链接:http://poj.org/problem?id=1523
题目来源:随便翻到的图论题,图论基础题。
简要题意:找出图的所有割点,和割完后连通块的个数。
数据范围: 1⩽N⩽1000
题解
是比较裸的割点题。
割点就是删去之后可以破坏剩下点的连通性的点。
只要稍加修改求割点的算法就能得到答案。
割点的求法是用 dep[x] 保存 x 的深度(或dfs序序号)low[x] 保存 x 及其后继节点连出的边中能达到的最小深度。
low[x] 初始置为 dep[x]
low[x]={min(low[next],low[x]) next is not visitedmin(dep[next],low[x]) next is visited算法的核心在于看当前点被删去后某子节点的后继能不能走回其祖先节点, low 数组就是记录这个信息的,不能的话割完,这个子节点和它的后继构成一个连通块,由于根的父节点没法构成连通块需要额外判断。判断条件为 x 为根时,可以超过一次访问子节点就是割点。
x 不为根时 low[child]⩾dep[x] 就是割点。
实现
本题只要看能被判成割点的个数就行了,这就是最终连通块的个数 −1 。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const int N = 1000+5;
struct Edge {
int to, nxt;
Edge(int to, int nxt) : to(to), nxt(nxt){}
Edge() {}
};
Edge e[N*100];
int res[N];
int dep[N];
int low[N];
int head[N];
void addEdge(int from, int to, int no) {
e[no] = Edge(to, head[from]);
head[from] = no;
}
void dfs(int x, int d) {
dep[x] = low[x] = d;
int cnt = 0;
for (int i = head[x]; ~i; i = e[i].nxt) {
int nxt = e[i].to;
if (!dep[nxt]) {
dfs(nxt, d+1);
cnt++;
low[x] = min(low[x], low[nxt]);
res[x] += x==1 ? cnt>1 : low[nxt] >= dep[x];
} else {
low[x] = min(low[x], dep[nxt]);
}
}
}
void init() {
memset(head, -1, sizeof head);
memset(res, 0, sizeof res);
memset(dep, 0, sizeof dep);
memset(low, 0, sizeof low);
}
void pr(int &cas) {
printf("Network #%d\n", cas++);
bool has = false;
for (int i = 1; i <= 1000; i++) {
if (res[i]) {
printf(" SPF node %d leaves %d subnets\n", i, res[i]+1);
has = true;
}
}
if (!has) puts(" No SPF nodes");
puts("");
}
int main()
{
int u, v, cas = 1;
while (scanf("%d", &u) == 1 && u) {
init();
int cnt = 0;
scanf("%d", &v);
addEdge(u, v, cnt++), addEdge(v, u, cnt++);
while (scanf("%d", &u) == 1 && u) {
scanf("%d", &v);
addEdge(u, v, cnt++), addEdge(v, u, cnt++);
}
dfs(1, 1);
pr(cas);
}
return 0;
}