poj 1523 SPF

  这是割顶题中的极为基础的一道,就是用了《数据结构》中的关节点(P178),或者说是刘汝佳的《算法艺术与信息学竞赛》中的割顶(P285)。我的理解和解释,就是如果当前结点的某个子结点的祖先的最低遍历编号不小于当前结点的遍历编号(这个解释必须这么长,因为无论是哪本书,对此的解释都是差不多的),那么当前结点就是所要找的割顶,而且割的是之前提及的某个子结点与在当前结点前被遍历的祖先的联系。

  这题可以直接套《数据结构》的FindArticul、DFSArticul函数,但是还要做的是思考怎样统计割顶的把整个图割成子连通分量的个数,因为题目要求求出割顶的同时,也要输出割顶把图分成多少部分。如果没有,就输出没有。

  这题要注意的是如果只输入一个0,这个不是一组数据,是不应该被处理的。我一开始wa的几次就只是因为这个,于是后来只好找题解帮忙。可是在我看到解题代码前,我找到一个标准数据,直接发现这个无聊的,但是poj又没有提及的注意事项。

 

我的代码除了头文件比较长,其他的是模仿《数据结构》的算法的,所以应该还是挺容易理解的:

 

View Code
  1 #include "cstdio"
  2 #include "cstdlib"
  3 #include "cstring"
  4 #include "cmath"
  5 #include "cctype"
  6 #include "vector"
  7 #include "set"
  8 #include "map"
  9 #include "string"
 10 #include "algorithm"
 11 #include "stack"
 12 #include "queue"
 13 
 14 #define INF 0x7fffffff
 15 #define reset(a) memset(a, 0, sizeof(a))
 16 #define copy(a, b) memcpy(a, b, sizeof(b))
 17 #define PI acos(-1)
 18 #define FMAX (1E300)
 19 #define MAX 1000000000
 20 #define feq(a, b) (fabs((a)-(b))<1E-6)
 21 #define flq(a, b) ((a)<(b)||feq(a, b))
 22 #define MAXN 10005
 23 #define BASE 137
 24 #define PASS puts("pass")
 25 #define filein freopen("test.in", "r", stdin)
 26 #define fileout freopen("test.out", "w", stdout)
 27 
 28 using namespace std;
 29 
 30 int e[1001][1001];
 31 int cnt, low[1001], vis[1001];
 32 int spf[1001];
 33 set<int> S;
 34 
 35 void dfs(int node){
 36     int min = ++cnt;
 37 
 38     vis[node] = cnt;
 39     for (int i = 1; i <= e[node][0]; i++){
 40         if (!vis[e[node][i]]){
 41             dfs(e[node][i]);
 42             if (min > low[e[node][i]])
 43                 min = low[e[node][i]];
 44             if (low[e[node][i]] >= vis[node])
 45                 spf[node]++;
 46         }
 47         else if (min > vis[e[node][i]])
 48             min = vis[e[node][i]];
 49     }
 50     low[node] = min;
 51 }
 52 
 53 int main(){
 54     int a, b, CASE = 1;
 55 
 56     //filein;
 57     //fileout;
 58     reset(e);
 59     S.clear();
 60     while (1){
 61         if (!~scanf("%d", &a))
 62             return 0;
 63         if (a){
 64             scanf("%d", &b);
 65             e[a][++e[a][0]] = b;
 66             e[b][++e[b][0]] = a;
 67             S.insert(a);
 68             S.insert(b);
 69         }
 70         else{
 71             if (!S.size())
 72                 continue;
 73             if (CASE != 1)
 74                 printf("\n");
 75             reset(vis);
 76             reset(spf);
 77             reset(low);
 78             bool pnt = false;
 79             cnt = 1;
 80             printf("Network #%d\n", CASE++);
 81 
 82             int begin;
 83 
 84             for (begin = 1; begin <= 1000; begin++)
 85                 if (S.count(begin))
 86                     break;
 87             low[begin] = vis[begin] = 1;
 88             for (int i = 1; i <= e[begin][0]; i++){
 89                 if (!vis[e[begin][i]]){
 90                     dfs(e[begin][i]);
 91                     if (cnt < S.size())
 92                         spf[begin]++;
 93                 }
 94             }
 95             for (int i = 1; i <= 1000; i++){
 96                 if (spf[i]){
 97                     printf("  SPF node %d leaves %d subnets\n", i, spf[i] + 1);
 98                     pnt = true;
 99                 }
100             }
101             if (!pnt)
102                 printf("  No SPF nodes\n");
103             reset(e);
104             S.clear();
105         }
106     }
107 }

 

 

——written by Lyon

转载于:https://www.cnblogs.com/LyonLys/archive/2012/05/14/poj_1523_Lyon.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值