http://blog.csdn.net/minjie_mj/archive/2010/07/13/5729843.aspx
通俗来说,割点就是在一个无向图中,去掉这个点以及与它关联的边,原来连通的图变为了若干不连通的块的一个点。求割点常见的算法就是DFS,在DFS时记录每个节点的深度dep和它的子孙所能达到的最浅深度low。然后对于每一个节点:
1) 如果u该点是根节点并且有两个或者两个以上儿子,那么u是一个割点
2) 如果u不是根节点并且存在它的一个儿子v,使得low[v] >= dep[u],那么u是割点
伪代码如下:
TOJ1026 http://acm.tju.edu.cn/toj/showp1026.html
- /* DFS求割点,在DFS时记录每个节点的深度dep和它的子孙所能达到的最浅位置low
- * 1)如果u根节点儿子大于1个,根节点为割点
- * 2)如果u不是根节点且对于u的子孙v有low[v]>=dep[u],u为一个割点
- * 注意输入和输出(输入用getchar() != '/n' 来控制一行 )
- */
- #include <cstdio>
- #include <cstring>
- #define M 102
- using namespace std;
- int map[M][M],low[M],dep[M];
- int f[M],n,depth,root;
- bool flag[M];
- int min( int a, int b){
- return a<b?a:b;
- }
- void dfs( int m){
- dep[m] = depth;
- low[m] = depth;
- depth++;
- flag[m] = true ;
- int i,j,k;
- for (i = 1;i <= n; i++){
- if (map[m][i]){
- if (!flag[i]){
- dfs(i);
- low[m] = min(low[m],low[i]);
- if (low[i] >= dep[m] && m != 1)
- f[m] ++;
- else if (m == 1) root ++;
- }
- else //有后向边
- low[m] = min(low[m],dep[i]);
- }
- }
- }
- int main()
- {
- int i,j,k;
- while (scanf( "%d" ,&n),n){
- memset(map,0,sizeof (map));
- memset(f,0,sizeof (f));
- memset(low,0,sizeof (low));
- memset(flag,false , sizeof (flag));
- memset(dep,0,sizeof (dep));
- root = 0;
- while (scanf( "%d" ,&k),k){
- while (getchar() != '/n' ){
- scanf("%d" ,&j);
- map[k][j] = map[j][k] = 1;
- }
- }
- root = 0;
- depth = 1;
- dfs(1);
- int ans = 0;
- if (root > 1) ans ++;
- for (i = 2;i <= n; i++)
- if (f[i]) ans ++;
- printf("%d/n" ,ans);
- }
- }
TOJ2189 http://acm.tju.edu.cn/toj/showp2189.html
- /* DFS求割点,在DFS时记录每个节点的深度dep和它的子孙所能达到的最浅位置low
- * 1)如果u根节点儿子大于1个,根节点为割点
- * 2)如果u不是根节点且对于u的子孙v有low[v]>=dep[u],u为一个割点
- * 注意输入和输出(输入用getchar() != '/n' 来控制一行 )
- */
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #define M 1002
- using namespace std;
- int low[M],dep[M],f[M];
- bool flag[M],map[M][M];
- int n,depth,root,cont;
- int min( int a, int b){
- return a<b?a:b;
- }
- void dfs( int m){
- dep[m] = depth;
- low[m] = depth;
- flag[m] = true ;
- depth++;
- int i,j;
- for (i = 1;i <= n; i++){
- if (map[m][i]){
- if (!flag[i]){
- dfs(i);
- low[m] = min(low[m],low[i]);
- if (low[i] >= dep[m] && m != 1)
- f[m] ++;
- else if (m == 1)
- root ++;
- }
- else
- low[m] = min(low[m],dep[i]);
- }
- }
- }
- int main()
- {
- int i,j,k;
- while (scanf( "%d" ,&n),n){
- memset(map,false , sizeof (map));
- memset(f,0,sizeof (f));
- memset(low,0,sizeof (low));
- memset(flag,false , sizeof (flag));
- while (scanf( "%d" ,&k),k){
- while (getchar() != '/n' ){
- scanf("%d" ,&j);
- map[k][j] = map[j][k] = true ;
- }
- }
- depth = 1; root = 0; cont = 0;
- dfs(1);
- int ans = 0;
- if (root > 1){
- ans ++;
- f[1]= 1;
- }
- for (i = 2;i <= n; i++)
- if (f[i]) ans ++;
- printf("%d" ,ans);
- if (ans > 0){
- int tep = 0; printf( " " );
- for (i = 1;i <= n; i++)
- if (f[i]){
- tep ++;
- printf("%d" ,i);
- if (tep != ans) printf( " " );
- else printf( "/n" );
- }
- }
- else printf( "/n" );
- }
- }
TOJ2299 http://acm.tju.edu.cn/toj/showp2299.html
- /* 给出一个无向图,计算去掉一个点后所能得到的最大块数
- * 1)每次DFS时num++,表示图的块数,然后在DFS过程中求出割点并且存下去掉割点连通分量增加的块数,
- * 注意根节点的f[root]最后要-1,因为1个儿子的根节点不会增加图的块数
- * 2)找到最大的f[i]和num相加即为所求,但是注意考虑特殊情况,零图
- *
- */
- #include <cstdio>
- #include <cstring>
- #include <vector>
- #define MAXN 10002
- using namespace std;
- int f[MAXN],low[MAXN],dep[MAXN];
- bool flag[MAXN];
- int n,depth,root,father,num,son;
- vector<int >mapp[MAXN];
- void DFS_CCS( int m){
- int i,u;
- low[m] = dep[m] = depth++;
- flag[m] = true ;
- for (i = 0;i < mapp[m].size(); i++){
- u = mapp[m][i];
- if (!flag[u]){
- DFS_CCS(u);
- if (low[u] >= dep[m]) f[m] ++;
- if (low[m] > low[u]) low[m] = low[u];
- }
- else if (low[m] > dep[u]) low[m] = dep[u];
- }
- }
- void cal_ccs(){
- int i,j;
- memset(flag,false , sizeof (flag));
- memset(low,0,sizeof (low));
- memset(f,0,sizeof (f));
- memset(dep,0,sizeof (dep));
- depth = 0; num = 0;
- for (i = 0;i < n; i++)
- if (!flag[i]){
- num ++;
- son = 0;
- father = i;
- DFS_CCS(i);
- if (f[father] != 0) f[father]--;
- }
- }
- int main()
- {
- int i,j,k,m;
- while (scanf( "%d%d" ,&n,&m)){
- if (m == 0 && n == 0) break ;
- for (i = 0;i < n; i++) mapp[i].clear();
- while (m--){
- scanf("%d%d" ,&i,&j);
- mapp[i].push_back(j);
- mapp[j].push_back(i);
- }
- cal_ccs();
- if (num == n) printf( "%d/n" ,n-1); //注意考虑零图的情况
- else {
- int mm = 0;
- for (i = 0;i < n; i++)
- if (f[i] > mm)
- mm = f[i];
- printf("%d/n" ,mm + num);
- }
- }
- }