poj 3352

题意:一个连通的无向图,求至少需要添加几条边,救能保证删除任意一条边,图仍然是连通的。

 

思路:边的双连通图。其实就是要求至少添加几条边,可以使整个图成为一个边双连通图。用tarjan算法(求割点割边)求出low数组,这里可以简化,然 后依据“low相同的点在一个边连通分量中”,缩点之后构造成树(这里可以直接利用low[]数组,low[i]即为第i节点所在的连通分量的标号)。求 出树中出度为1的节点数left,答案即为(leaf+1)/2。

代码:

#include<iostream>
#include<fstream>
using namespace std;

int n,m;

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

e edge[1001];

int in[1001],dfn[1001],sta[1001],low[1001],scc[1001];
int top,index,sum;

void tar(int s,int f){
	int i,j,k;
	low[s]=dfn[s]=++index;
	sta[++top]=s;
	e *p=edge[s].next;
	while(p){
		if(p->data==f)
		{
			p=p->next;
			continue;
		}
		if(dfn[p->data]==0)
		{
			tar(p->data,s);
			low[s]=min(low[s],low[p->data]);
		}
		else
			low[s]=min(low[s],dfn[p->data]);
		p=p->next;
	}
	if(low[s]==dfn[s])
	{
		sum++;
		do{
			i=sta[top--];
			scc[i]=sum;
		}while(i!=s);
	}
}


void solve(){
	int i,j,k;
	index=0;sum=0;
	memset(dfn,0,sizeof(dfn));
	memset(in,0,sizeof(in));
	for(i=1;i<=n;i++)
		if(dfn[i]==0)
			tar(i,0);
	for(i=1;i<=n;i++)
	{
		e *p=edge[i].next;
		while(p){
			if(scc[p->data]!=scc[i])
			{
				in[scc[p->data]]++;
				in[scc[i]]++;
			}
			p=p->next;
		}
	}
	j=0;
	for(i=1;i<=sum;i++)
		if(in[i]==2)
			j++;
	cout<<(j+1)/2<<endl;

}



void read(){
//	ifstream cin("in.txt");
	int i,j,k,s,t;
	while(cin>>n>>m)
	{
		for(i=1;i<=n;i++)
			edge[i].next=0;

		for(i=1;i<=m;i++)
		{
			cin>>s>>t;
			e *p=new e;
			p->data=t;
			p->next=edge[s].next;
			edge[s].next=p;

			e *q=new e;
			q->data=s;
			q->next=edge[t].next;
			edge[t].next=q;

		}
		solve();
	}
}

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

posted on 2011-05-17 19:28  宇宙吾心  阅读(972)  评论(0)    收藏  举报

导航