POJ1523:SPF——题解
http://poj.org/problem?id=1523
这题明显就是求割点然后求割完之后的强连通分量的个数。
割点都会求,怎么求割完的分量个数呢?
我们可以通过万能的并查集啊!(具体做法看代码吧,方法不好叙述)
这样我们查割点它所连的点一共隶属于几个集合即可。
(PS:读入方式很恶心,同时请注意快速读入)
#include<stack> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; inline int read(){ int x=0,w=1;char ch=0; while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*w; } const int maxn=1001; bool dis[maxn][maxn]; bool cut[20001]; int dfn[maxn]; int low[maxn]; int fa[maxn]; int from[maxn]; int t; int big[maxn]; int to[maxn]; int find(int a){ if(a==fa[a])return a; return fa[a]=find(fa[a]); } void tarjan(int u,int f){ bool tong[maxn]={0}; from[u]=f; t++; dfn[u]=t; low[u]=t; to[t]=u; for(int v=1;v<=maxn;v++){ if(dis[u][v]){ if(!dfn[v]){ tarjan(v,u); low[u]=min(low[u],low[v]); }else if(f!=v){ low[u]=min(low[u],dfn[v]); } } fa[find(u)]=find(to[low[u]]); } for(int v=1;v<=maxn;v++){ if(dis[u][v]){ if(!tong[find(v)]){ tong[find(v)]=1; big[u]++; } } } return; } int main(){ int u,v; int cnt=0; bool smg=0; while(233){ int u=read(); if(!u&&!smg)break; smg=1; if(!u){ for(int i=1;i<=maxn;i++)fa[i]=i; tarjan(1,0); int rootson=0; bool ok=0; for(int i=2;i<=maxn;i++){ int v=from[i]; if(v==1)rootson++; else{ if(low[i]>=dfn[v]&&low[i]&&dfn[i]){ cut[v]=1; ok=1; } } } if(rootson>=2){ cut[1]=1; ok=1; } cnt++; printf("Network #%d\n",cnt); if(ok==0){ printf(" No SPF nodes\n"); }else{ for(int i=1;i<=maxn;i++){ if(cut[i])printf(" SPF node %d leaves %d subnets\n",i,big[i]); } } printf("\n"); memset(cut,0,sizeof(cut)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(fa,0,sizeof(fa)); memset(from,0,sizeof(from)); memset(dis,0,sizeof(dis)); memset(big,0,sizeof(big)); memset(to,0,sizeof(to)); t=0; smg=0; continue; } int v=read(); dis[u][v]=dis[v][u]=1; } return 0; }