POJ 1523 SPF (割頂 點雙連通分量)

題意就是求出在一個圖上去除一個點之後,那個圖會變成多少個子連通圖。

顯然我們要求出割頂。我的代碼套用了劉汝佳的大白書的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");
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章