POJ 1523 SPF(Tarjan 求解连通分量)

题目大意:给定的通信设备之间的关系,问有没有割点,并输出去掉割点后的连通分量的个数。

思路:裸的Trajan求解割点,当某个点为割点的条件是low[v]>=dfn[u],或者是根节点且孩子的数目>=2。连通分量的个数=符合条件孩子数目+1.

#include<map>
#include<queue>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#include<algorithm>
#define LL long long
#define inf 0x3f3f3f3f
const double PI=acos(-1.0);
using namespace std;
bool mp[1010][1010],vis[1010];
int n,m,cnt,dfn[1010],low[1010],son,subnet[1010],sum;
void init(){
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,false,sizeof(vis));
    memset(subnet,0,sizeof(subnet));
    son=0;sum=1;dfn[1]=low[1]=1;vis[1]=true;
}
int Tarjan(int x){

    for(int i=1;i<=cnt;i++){
        if(mp[x][i]){
            if(!vis[i]){
                vis[i]=true;
                low[i]=dfn[i]=++sum;
                Tarjan(i);
                low[x]=min(low[x],low[i]);
                if(low[i]>=dfn[x]){
                    if(x!=1)
                        subnet[x]++;
                    else
                        son++;
                }
            }
            else
                low[x]=min(low[x],dfn[i]);
        }
    }
}
int main(){
    int i,j,k,a,b,cla=1;
    while(~scanf("%d",&n)&&n){
        cnt=0;
        memset(mp,false,sizeof(mp));
        scanf("%d",&m);
        cnt=max(n,m);
        mp[n][m]=mp[m][n]=true;
        while(~scanf("%d",&a)&&a){
            scanf("%d",&b);
            mp[a][b]=mp[b][a]=true;
            cnt=max(cnt,max(a,b));
        }
        printf("Network #%d\n",cla++);
        init();
        Tarjan(1);
        bool bj=false;
        if(son>1) subnet[1]=son-1;
        for(i=1;i<=cnt;i++){
            if(subnet[i]){
                printf(" SPF node %d leaves %d subnets\n",i,subnet[i]+1);
                bj=true;
            }
        }
        if(!bj)
            printf(" No SPF nodes\n");
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(poj,Tarjan,连通分量)