Poj 1523 SPF(割点 + tarjan算法)

来源:互联网 发布:怎么授权给软件 编辑:程序博客网 时间:2024/05/01 17:53

http://poj.org/problem?id=1523

题意:给一个连通网络,其节点数目<= 1000,求出其割点编号,并求出删除该割点后会被分割成几个连通块。


思路:

tarjan算法:从第一个节点开始深度优先搜索,同时记录每个节点i的访问次序以及该节点所能到达的最高辈分(深度最低)的祖先,对这两个数比较确定这个点是否是割点;同时用subnets数组记录,若是割点并且是搜索树的根节点,则它的儿子数就是删除节点 i 后得到的连通分量,若是割点并且是非根节点,当第一次遍历到该节点时还不能确定它是不是割点,之后对于该节点的每一棵子树若能判断出该节点是割点,则subnets[i]加1.


#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>using namespace std;const int maxn = 1010;vector <int> edge[maxn];//邻接表存储int subnets[maxn];//记录节点是否为割点,当是割点时记录删除它后的连通分量数int dfn[maxn];//深度优先搜索时的次序(时间戳)int low[maxn];//能追溯到的深度最浅的祖先int vis[maxn];//是否访问过int cnt;int son;//根节点儿子数int maxv;//最大节点数void Init(){memset(vis,0,sizeof(vis));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(subnets,0,sizeof(subnets));cnt = 0;son = 0;}void tarjan(int u){vis[u] = 1;dfn[u] = low[u] = ++cnt;for(int i = 0; i < (int)edge[u].size(); i++){int v = edge[u][i];if(!vis[v]){tarjan(v);low[u] = min(low[u],low[v]);if(low[v] >= dfn[u])//u是割点{if(u >= 2)subnets[u]++;else son++;}}elselow[u] = min(low[u],dfn[v]);}}void output(int item){int flag = 0;printf("Network #%d\n",item);if(son > 1)subnets[1] = son - 1;for(int i = 1; i <= maxv; i++){if(subnets[i]){flag = 1;subnets[i] += 1;printf("  SPF node %d leaves %d subnets\n",i,subnets[i]);}}if(!flag)printf("  No SPF nodes\n");printf("\n");}int main(){int u,v,f,flag;for(int item = 1; ; item++){for(int i = 1; i <  maxn; i++)edge[i].clear();f = 0;maxv = -1;while(1){scanf("%d",&u);maxv = max(maxv,u);if(u == 0 && f == 0){flag = 1;//输入结束break;}if(u == 0 && f != 0){flag = 2;//改组输入结束break;}scanf("%d",&v);maxv = max(maxv,v);f = 1;edge[u].push_back(v);edge[v].push_back(u);}if(flag == 2){Init();tarjan(1);output(item);}if(flag == 1)break;}return 0;}


0 0
原创粉丝点击