poj1523 最小割+并查集

来源:互联网 发布:mac skype 下载 编辑:程序博客网 时间:2024/05/01 18:52

题目链接:http://poj.org/problem?id=1523
题意是给你一些点,每两个点连成一条边,问图中有几个割点,同时如果去除割点后,图中有多少个能够互相联通的集合,比较坑的是点不是按顺序给的,即可能不是从1开始。
求割点直接套割点模板,去除割点后,还有多少能够互相联通的点的集合,可以求出割点后,对割点dfs,凡是两个不含割点的点,并到一个集合中,最后看有多少个集合即可。
代码:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int spot=1010;const int edge=500010;struct stu{    int to,next;} a[edge];int head[spot],low[spot],num[spot],root,indexx,sizes,flag1,n,fx[spot];  //fx指祖节点bool flag[spot],flag2[spot],b[spot],have[spot];void init(){    indexx=0,sizes=0,flag1=1,n=0;    memset(head,-1,sizeof(head));    memset(low,0,sizeof(low));    memset(num,0,sizeof(num));    memset(flag,0,sizeof(flag));    memset(have,0,sizeof(have));}void add_edge(int from,int to)  //并查集{    a[sizes].to=to;    a[sizes].next=head[from];    head[from]=sizes++;    a[sizes].to=from;    a[sizes].next=head[to];    head[to]=sizes++;    n=max(n,from);    n=max(n,to);}void dfs(int cur,int father)  //求割点{    int child=0;    num[cur]=++indexx;    low[cur]=indexx;    int k,v;    for(k=head[cur]; k+1; k=a[k].next)    {        v=a[k].to;        if(!num[v])        {            child++;            dfs(v,cur);            low[cur]=min(low[cur],low[v]);            if(cur!=root&&num[cur]<=low[cur])                flag[cur]=1;            if(cur==root&&child==2)                flag[cur]=1;        }        else if(v!=father)            low[cur]=min(low[cur],num[v]);    }}int finds(int x){    while(fx[x]!=x)        return fx[x]=finds(fx[x]);    return x;}void mix(int x,int y){    int ffx=finds(x),ffy=finds(y);    if(ffx!=ffy)        fx[ffx]=ffy;}void dfs_edge(int x,int j)  //x下一个节点,j不能等的那个{    int v,k;    for(k=head[x]; k+1; k=a[k].next)    {        v=a[k].to,b[x]=1;        if(!b[v])        {            dfs_edge(v,j);            if(x!=j)                mix(x,v);        }    }}int main(){    int x,y,i,ss=0,ans,j;    while(scanf("%d",&x)&&x)    {        init();        scanf("%d",&y);        root=x;            have[x]=1;        have[y]=1;        add_edge(x,y);        for(;;)        {            scanf("%d",&x);            if(!x) break;            scanf("%d",&y);            add_edge(x,y);            have[x]=1,have[y]=1;        }        dfs(root,root);  //求割点        printf("Network #%d\n",++ss);        for(i=1; i<=n; i++)        {            if(flag[i])  //dfs遍历边的同时,将相邻的两条点(不包含i)并到一个集,最后判断有几个集合,即去掉割点后,还剩多少个集合            {                ans=0,flag1=0;                for(j=1; j<=n; j++)                    if(have[j])                    fx[j]=j;                memset(b,0,sizeof(b));                memset(flag2,0,sizeof(flag2));                dfs_edge(i,i);                 for(j=1; j<=n; j++)                    flag2[finds(j)]=1;                for(j=1; j<=n; j++)                    if(flag2[j]&&j!=i&&have[j])                        ans++;                printf("  SPF node %d leaves %d subnets\n",i,ans);            }        }        if(flag1)            printf("  No SPF nodes\n");            puts("");    }    return 0;}
0 0
原创粉丝点击