zoukankan      html  css  js  c++  java
  • POJ 1523 SPF (割点,连通分量)

    题意:给出一个网络(不一定连通),求所有的割点,以及割点可以切分出多少个连通分量。

    思路:很多种情况。

    (1)如果给的图已经不是连通图,直接“  No SPF nodes”。

    (2)求所有割点应该不难,就是tarjan发明的算法搞定。但是求连通分量就得小心了,多种情况。看下:

      1)如果一个割点x,其所有孩子都不是割点,那么x至少可以割出两个连通分量(x之上和之下的各1个)。

      2)如果一个割点x,其有部分孩子是割点,有部分孩子并不是割点,那么x可以割出x之上的1个连通分量,不是割点的孩子均是同1个连通分量,是割点的孩子各自分别是一个连通分量。

      3)如果一个割点x,如果有些孩子是叶子节点,且该叶子节点的度为1,即连着x,那么该叶子节点会被割出来,单点也是连通分量。

      1 //#include <bits/stdc++.h>
      2 #include <iostream>
      3 #include <cmath>
      4 #include <cstdio>
      5 #include <vector>
      6 #include <cstring>
      7 #include <climits>
      8 using namespace std;
      9 const int N=1005;
     10 int mapp[N][N];
     11 int cntr, flag, up;                       //时间戳
     12 int dfn[N], low[N], vis[N], iscut[N], cur[N];     //记录时间戳, 反边最顶点, 访问记录, 是否连通分量
     13 
     14 bool DFS(int x, int far)
     15 {
     16     int chd=0;              //孩子节点个数
     17     int cnt=0, sum=0;
     18     dfn[x]=low[x]=++cntr;   //时间戳
     19     vis[x]=1;               //DFS必备
     20     for(int i=1; i<=up; i++)
     21     {
     22         if(!mapp[i][x]) continue;
     23         if(!vis[i])         //树边
     24         {
     25             chd++;
     26             bool f=DFS(i,x);    //i点只有一条边
     27             low[x]=min(low[x],low[i]);
     28 
     29             //判断连通分量的个数
     30             if(!far && chd>1 || far && low[i]>=dfn[x] )   //能让x成为割点的孩子i
     31             {
     32 
     33 
     34                 sum++;
     35                 iscut[x]=1;
     36                 if(iscut[i]||f)    cnt++;      //这个孩子是割点或者满足单点单边条件
     37             }
     38         }
     39         else if(i!=far)
     40             low[x]=min(low[x], dfn[i]);
     41     }
     42     if(!far && iscut[x])
     43     {
     44         iscut[x]=cnt;  //根节点
     45         if(sum>cnt) iscut[x]++;
     46     }
     47     if( far && iscut[x])    //非根节点
     48     {
     49         if(!cnt )     iscut[x]=2;    //没有“是割点”的孩子,那么只要自己是割点,起码可以割为两个连通分量
     50         else if(sum==cnt)    iscut[x]=cnt+1;     //有“是割点”的孩子,那么每个“割点”孩子是1个连通分量,注:有可能还有非割点孩,他们算1个连通分量
     51         else iscut[x]=cnt+2;
     52     }
     53     if(iscut[x])    flag=1; //无割点的标记'
     54     //if(x==1)    cout<<"**"<<sum<<endl;
     55 
     56     if(!chd && low[x]==dfn[x] )   return true;  //返回值用于判断是否是叶子,且没有反向边到fa之上
     57     return false;
     58 }
     59 
     60 
     61 void cal()  //n为边数
     62 {
     63 
     64     flag=cntr=0;
     65     DFS(up,0);  //深搜求割点数
     66     int i;
     67     for(i=1; i<=up; i++)    //先确保是个连通图
     68         if(cur[i]&&!vis[i])
     69         {
     70             printf("  No SPF nodes
    ");
     71             return ;
     72         }
     73 
     74     for(i=1; i<=up; i++)
     75         if(cur[i]&&iscut[i])
     76         {
     77             printf("  SPF node %d leaves %d subnets
    ", i, iscut[i]);
     78         }
     79 
     80     if(!flag)   printf("  No SPF nodes
    ");
     81 }
     82 void init()
     83 {
     84     up=0;
     85     memset(cur,0,sizeof(cur));
     86     memset(mapp,0,sizeof(mapp));
     87     memset(vis,0,sizeof(vis));
     88     memset(dfn,0,sizeof(dfn));
     89     memset(low,0,sizeof(low));
     90     memset(iscut,0,sizeof(iscut));
     91 
     92 }
     93 
     94 int main()
     95 {
     96     freopen("input.txt", "r", stdin);
     97     int j=0, a, b;
     98     while(1)
     99     {
    100         int cnt=0;
    101         init();
    102         while(~scanf("%d",&a))
    103         {
    104             if(!a && !cnt)    return 0;   //没边,a又为0,则结束了
    105             if(!a)
    106             {
    107                 printf("Network #%d
    ",++j);
    108                 cal();
    109                 printf("
    ");break;
    110             }
    111             scanf("%d",&b);
    112             up=max(max(up,a),b);    //记录顶点号上限
    113             cur[a]=cur[b]=1;        //记录出现的顶点号
    114             mapp[a][b]=mapp[b][a]=1;    //矩阵
    115             cnt++;                  //边数
    116         }
    117     }
    118     return 0;
    119 }
    AC代码
  • 相关阅读:
    关于一个标准的poi下载文件模板 可拿来来直接使用
    关于史上最简单的导出(导出excal)
    关于spring MVC的面试题
    关于响应式布局(pc端访问自适应 手机端访问自适应)
    密码生成器
    关于poi的导出(POI)
    关于MUI一个很实用的前端框架
    (转载)插画版Kubernetes指南(小孩子也能看懂的kubernetes教程)
    (转载)Python tips: 什么是*args和**kwargs?
    python编程中的if __name__ == 'main': 的作用和原理
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4616270.html
Copyright © 2011-2022 走看看