poj1523 - SPF

来源:互联网 发布:淘宝网上怎么买东西 编辑:程序博客网 时间:2024/04/27 17:25

                                  想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
                                  转载请注明出处:http://blog.csdn.net/wangjian8006

 

题目大意:拿左边的图举例,有一个网络,在这个网络只能是点对点通信,如果3号节点出故障了,那么1号节点与2号节点,4号节点和5号节点还是可以通信的,不过1,2号不能和4,5号节点通信了。这样3号节点就是一个SPF节点,并且当3号节点出故障了分为了2个子网络
差不多就是说与许多点,有些点之间有无向边,问删除某个点之后,可以将图分为几块

 

 

解题思路:一个裸的求割点的题目,割点的定义是,在一个连通图,删除某一个点之后,这个图不再连通,那么称这个点为割点,又可以叫关节点,而分为几块的意思是求删除这个点之后有多少个连通分量
一个暴力算法是,将每个点删除之后求连通分量再恢复这个点,但是时间复杂度是O(n^3)

但是根据定理用tarjan算法可以以O(n^2)的时间复杂度求出:
点x是关节点的充分必要条件是
1.x是深搜的生成树的树根,那么如果x有2个以上的孩子结点,那么x是割点,并且连通分量就是孩子结点的数目
2.x不是树根,那么如果x有一个孩子结点,使得dfn[x]<=low[y],那么x也是一个割点,连通分量就是,看有多少个孩子
结点的符合这个条件,连通分量=符合条件的孩子数目+1

注:dfn代表深搜的先后顺序,low代表最低深度优先数,如果不懂,可以去了解下tarjan算法

tarjan:http://blog.csdn.net/wangjian8006/article/details/7892084

 

/*Memory 1172KTime    16MS */#include <iostream>using namespace std;#define MAXV 1010#define min(a,b) (a>b?b:a)bool map[MAXV][MAXV];//保存图int rcnt;//记录输入的结点int dfn[MAXV],low[MAXV];//深度与最低深度优先数bool vis[MAXV];//标记结点是否被寻找int son;//树根的子女结点的个数int subnets[MAXV];//记录删除i点后的连通分量int count;//记录访问void init(){memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(vis,0,sizeof(vis));memset(subnets,0,sizeof(subnets));son=0;count=1;dfn[1]=low[1]=1;//对根节点初始化vis[1]=1;}void dfs(int x){//tajrjanfor(int i=1;i<=rcnt;i++){if(map[x][i]){if(!vis[i]){vis[i]=1;dfn[i]=low[i]=++count;dfs(i);low[x]=min(low[x],low[i]);if(low[i]>=dfn[x]){if(x!=1) subnets[x]++;if(x==1) son++;}}else low[x]=min(low[x],dfn[i]);}}}void work(){init();dfs(1);}void Output(){int flag=0;if (son>1) subnets[1]=son-1;//到时候输出要+1for(int i=1;i<=rcnt;i++){if(subnets[i]){printf("  SPF node %d leaves %d subnets\n",i,subnets[i]+1);flag=1;}}if(!flag) printf("  No SPF nodes\n");printf("\n");}void cntv(int x){rcnt=(rcnt>x?rcnt:x);}int main(){//freopen("d:\\test.in","r",stdin);int a,b,Case=0;while(scanf("%d",&a) && a){memset(map,0,sizeof(map));scanf("%d",&b);map[a][b]=map[b][a]=1;rcnt=0;cntv(a),cntv(b);while(scanf("%d",&a) && a){scanf("%d",&b);map[a][b]=map[b][a]=1;cntv(a),cntv(b);}work();printf("Network #%d\n",++Case);Output();}return 0;}


 

 

原创粉丝点击