poj 2117

题意:一个无向图,现在要去掉其中一个点,要求去掉这个点之后,总连通分支数最大。

 

思路:割点,连通分量。主要分三种情况:

1、最普通的情况:如果有边,而且存在割点,就是tarjon算法的深搜过程中求出所有割点的子树的个数(其实也就是如果去掉割点,能使连通分支数增加的个数)的最大值,再加上原来的强连通分支数即可。

2、最容易出错的情况:如果没有边,则应该去掉一个点后,连通分支数为原顶点数减去1。

3、如果有边,但是图中不存在割点,则输出原来图中连通分支数就行了。

代码:

#include<iostream>
#include<fstream>

using namespace std;

int m,n;

struct e{
	int data;
	e *next;
};

e edge[10011];
int dfn[10011],cnt[10011],low[10011];
int index;

void tar(int s){
	dfn[s]=low[s]=++index;
	cnt[s]=0;
	e *p=edge[s].next;
	while(p){
		
		if(dfn[p->data]==0)
		{
			tar(p->data);
			if(low[p->data]>=dfn[s])
			{
				cnt[s]++;
			}
			low[s]=min(low[s],low[p->data]);
		}
		else
	
			{
				low[s]=min(low[s],dfn[p->data]);
			}
		p=p->next;
	}
}
	
void solve(){
	int i,j=0,k;
	index=0;
	memset(dfn,0,sizeof(dfn));
	for(i=0;i<n;i++)
	{
		if(dfn[i]==0)
		{
			j++;
			tar(i);
			cnt[i]--;
		}
	}

	k=0;
	
	for(i=0;i<n;i++)
		k=max(k,cnt[i]);
	if(m==0) cout<<n-1<<endl;
	else	cout<<j+k<<endl;
}

void read(){
//	ifstream cin("in.txt");
	int i,j,k,s,t;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0) return;
		for(i=0;i<n;i++)
			edge[i].next=0;
		for(i=1;i<=m;i++)
		{
//			cin>>s>>t;
			scanf("%d%d",&s,&t);
			e *p=new e;
			p->data=s;
			p->next=edge[t].next;
			edge[t].next=p;
			
			e *q=new e;
			q->data=t;
			q->next=edge[s].next;
			edge[s].next=q;

		}
		solve();
	}
}


int main(){
	read();
	return 0;
}

posted on 2011-05-17 18:54  宇宙吾心  阅读(666)  评论(0)    收藏  举报

导航