POJ 1523 SPF 割边与割点

来源:互联网 发布:mysql 转义符号 编辑:程序博客网 时间:2024/05/01 15:09

本题要求出割点,并算出每个割点将图分成几个分支。

用tarjan算法求的割点,然后对每个割点,dfs求有多少个分支

每点的数是不一定的,我用的set存的点,vector存的图

求多少个分支就是:如果i是割点,就对与i相连的点的分支进行dfs标记,

假如与i相连的第j个点标记完了,标记第j+1个点时,发现j+1点标记过了,则j+1点和之前的某点在同一分支上,则不 sum++;

大概就是这样,自己画图感受一下吧!

注意:每组用例后腰输出一个空行,”那个“之前还有两个空格

#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>#include<set>using namespace std;set<int> s;int low[1010],dfn[1010],vis[1010],shi[1010];int f[1010];vector<int> q[1010];int n,m,ntime,root,flag,flag1;//flag判断是否有割点,flag1判断是否输入结束void dfs(int u,int fa)//递归标记被走过的点{for(int i=0;i<q[u].size();i++){int v=q[u][i];if(v!=fa && shi[v]==0){shi[v]=1;dfs(v,u);}}}void tarjan(int u,int father)//求low[]和dfn[]{f[u]=father;int i,j,k;low[u]=dfn[u]=ntime++;for(i=0;i<q[u].size();i++){int v=q[u][i];if(!dfn[v]){tarjan(v,u);low[u]=min(low[u],low[v]);}else if(father!=v)low[u]=min(low[u],dfn[v]);}}void count(){int nroot=0,i;tarjan(root,0);set<int>::iterator it=s.begin();for(it++;it!=s.end();it++){int v=f[*it];if(v==root)nroot++;else{if(dfn[v]<=low[*it]){vis[v]=1;flag=1;}}}if(nroot>1) {vis[root]=1;flag=1;}int sum;for(it=s.begin();it!=s.end();it++){if(vis[*it]==1){memset(shi,0,sizeof(shi));sum=0;int u=*it;shi[u]=1;for(i=0;i<q[u].size();i++){int v=q[u][i];if(shi[v]==0)//与个点相连的v点没标记过{sum++;shi[v]=1;//标记该点dfs(v,u);//标记以该点为根节点的分支}}printf("  SPF node %d leaves %d subnets\n",u,sum);}}}int main(){int i,j,k,ans=0;memset(vis,0,sizeof(vis));//各种初始化memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(f,0,sizeof(f));for(i=0;i<1010;i++)q[i].clear();s.clear();flag=0;flag1=0;while(scanf("%d",&n)!=EOF){if(n!=0) {flag1=1;scanf("%d",&m);q[n].push_back(m);q[m].push_back(n);s.insert(n);s.insert(m);continue;}if(flag1==0) break;set<int>::iterator it=s.begin();root=*it;ntime=1;ans++;printf("Network #%d\n",ans);count();if(flag==0)printf("  No SPF nodes\n");printf("\n");memset(vis,0,sizeof(vis));//各种初始化memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(f,0,sizeof(f));for(i=0;i<1010;i++)q[i].clear();s.clear();flag=0;flag1=0;}return 0;}

刚才又和同学交流了一下,求割点的分支那个不用dfs,

对于割点u,找i的儿子v,也就是点v满足f[v]==u,如果low[v]>=dfn[u],则sum++;  具体原理我也不是太懂。。自己研究一下吧

另外,如果u是根节点,则不用sum++,如果u不是根节点,他的父亲还有一个分支,所以要sum++;

#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>#include<set>using namespace std;set<int> s;int low[1010],dfn[1010],vis[1010];int f[1010];vector<int> q[1010];int n,m,ntime,root,flag,flag1;void tarjan(int u,int father){f[u]=father;int i,j,k;low[u]=dfn[u]=ntime++;for(i=0;i<q[u].size();i++){int v=q[u][i];if(!dfn[v]){tarjan(v,u);low[u]=min(low[u],low[v]);}else if(father!=v)low[u]=min(low[u],dfn[v]);}}void count(){int nroot=0,i;tarjan(root,0);set<int>::iterator it=s.begin();for(it++;it!=s.end();it++){int v=f[*it];if(v==root)nroot++;else{if(dfn[v]<=low[*it]){vis[v]=1;flag=1;}}}if(nroot>1) {vis[root]=1;flag=1;}int sum;for(it=s.begin();it!=s.end();it++){if(vis[*it]==1){sum=0;int u=*it;if(u!=root) //如果是根节点,则不用sum++,如果不是根节点,他的父亲还有一个分支,所以要sum++;sum++;for(i=0;i<q[u].size();i++){int v=q[u][i];if(f[v]==u && low[v]>=dfn[u]) //这判断一下{sum++;}}printf("  SPF node %d leaves %d subnets\n",u,sum);}}}int main(){int i,j,k,ans=0;memset(vis,0,sizeof(vis));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(f,0,sizeof(f));for(i=0;i<1010;i++)q[i].clear();s.clear();flag=0;flag1=0;while(scanf("%d",&n)!=EOF){if(n!=0) {flag1=1;scanf("%d",&m);q[n].push_back(m);q[m].push_back(n);s.insert(n);s.insert(m);continue;}if(flag1==0) break;set<int>::iterator it=s.begin();root=*it;ntime=1;ans++;printf("Network #%d\n",ans);count();if(flag==0)printf("  No SPF nodes\n");printf("\n");memset(vis,0,sizeof(vis));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(f,0,sizeof(f));for(i=0;i<1010;i++)q[i].clear();s.clear();flag=0;flag1=0;}return 0;}


原创粉丝点击