題意就是求出在一個圖上去除一個點之後,那個圖會變成多少個子連通圖。
顯然我們要求出割頂。我的代碼套用了劉汝佳的大白書的tarjan算法,用一個數組cnt[]記錄一個點是多少個點雙連通分量的割頂。當發現一個點是割頂的時候,就cnt[i]++。最後,如果一個點是一棵dfs樹的樹根時,就輸出cnt[i],否則就輸出cnt[i]+1(因爲那個點有父親,而cnt數組記錄的相當於是該點的兒子個數)。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<climits>
#include<stack>
using namespace std;
struct Edge
{
int u,v;
Edge(int uu,int vv)
{
u=uu;v=vv;
}
Edge(){}
};
const int maxn=1005;
int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;
vector<int>G[maxn],bcc[maxn];
vector<pair<int,int> > ans;
int cnt[maxn];
bool isfa[maxn];
stack<Edge>s;
int dfs(int u,int fa)
{
int lowu=pre[u]=++dfs_clock;
int child=0;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
Edge e=Edge(u,v);
if(!pre[v])
{
s.push(e);
child++;
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
if(lowv>=pre[u])
{
iscut[u]=true;cnt[u]++;
bcc_cnt++;bcc[bcc_cnt].clear();
for(;;)
{
Edge x=s.top();s.pop();
if(bccno[x.u]!=bcc_cnt){bcc[bcc_cnt].push_back(x.u);bccno[x.u]=bcc_cnt;}
if(bccno[x.v]!=bcc_cnt){bcc[bcc_cnt].push_back(x.v);bccno[x.v]=bcc_cnt;}
if(x.u==u&&x.v==v) break;
}
}
}
else if(pre[v]<pre[u]&&v!=fa)
{
s.push(e);
lowu=min(lowu,pre[v]);
}
}
if(fa<0)
{
isfa[u]=true;
if(child==1) iscut[u]=false;
}
return lowu;
}
void find_bcc(int n)
{
memset(pre,0,sizeof(pre));
memset(iscut,0,sizeof(iscut));
memset(bccno,0,sizeof(bccno));
memset(isfa,0,sizeof(isfa));
dfs_clock=bcc_cnt=0;
for(int i=0;i<n;i++)
if(!pre[i]) dfs(i,-1);
}
int main()
{
int u,v;
bool flag=true;
int cas=0;
while(flag)
{
int maxed=-1;
for(int i=0;i<=1000;i++) G[i].clear();
memset(cnt,0,sizeof(cnt));
ans.clear();
bool valid=false;
while(1)
{
if(scanf("%d",&u)!=EOF)
{
if(0==u) break;
if(u>maxed) maxed=u;
scanf("%d",&v);
if(v>maxed) maxed=v;
valid=true;
u--,v--;
G[u].push_back(v);
G[v].push_back(u);
}
else {flag=false;break;}
}
if(!flag) break;
if(valid==false) break;
find_bcc(maxed);
bool hascut=false;
for(int i=0;i<maxed;i++)
{
if(iscut[i])
{
hascut=true;
if(!isfa[i])ans.push_back(make_pair(i+1,cnt[i]+1));
else ans.push_back(make_pair(i+1,cnt[i]));
}
}
cas++;
printf("Network #%d\n",cas);
if(!hascut)
printf(" No SPF nodes\n");
else
{
for(int i=0;i<ans.size();i++)
{
printf(" SPF node %d leaves %d subnets\n",ans[i].first,ans[i].second);
}
}
printf("\n");
}
}