poj 3177

第一道双联通的题目,求加几条边让原图成一个双联通图,求出度数为1的双联通分量的个数+1/2、

Low[u]为u或u的子树中能通过非父子边追溯到的最早的节点,即DFS序号最小的节点的序号







 

#include<stdio.h>

#include<stack>

#include<string.h>

#define N 5010

using namespace std;

int n,m,first[N],num,low[N],dfs[N],idx,ans,vis[N],degree[N],belong[N];

struct edge

{

	int ed,next;

}E[10010];

void addedge(int x,int y)

{

	E[num].ed=y;

	E[num].next=first[x];

	first[x]=num++;

}

stack<int>Q;

void Tarjan(int u,int father)

{

	

	low[u]=dfs[u]=idx++;

	vis[u]=1;

	Q.push(u);

	for(int p=first[u];p!=-1;p=E[p].next)

	{

		int v=E[p].ed;

		if(v==father){continue;}

		if(!vis[v])Tarjan(v,u);

		low[u]=low[u]>low[v]?low[v]:low[u];

	}

	int x;

	if(low[u]==dfs[u])

	{

		do

		{

			x=Q.top();

			Q.pop();

			vis[x]=0;

			belong[x]=ans;//缩点

		}while(x!=u);

		ans++;

	}

}

int judge(int x,int y)

{

	for(int p=first[x];p!=-1;p=E[p].next)

		if(E[p].ed==y)

			return 0;

		return 1;

}

int main()

{

	int i,x,y,sum;

	while(scanf("%d%d",&n,&m)!=-1)

	{

		memset(first,-1,sizeof(first));

		num=0;

		for(i=0;i<m;i++)

		{

			scanf("%d%d",&x,&y);

			if(judge(x,y)==1)//去掉重边

			{

				addedge(x,y);

				addedge(y,x);

			}

		}

		memset(vis,0,sizeof(vis));

		idx=ans=0;

		Tarjan(1,0);

		memset(degree,0,sizeof(degree));

		for(i=1;i<=n;i++)

		{

			for(int p=first[i];p!=-1;p=E[p].next)

			{

				int v=E[p].ed;

				if(belong[i]!=belong[v])

					degree[belong[v]]++;

			}

		}

		sum=0;

		for(i=0;i<ans;i++)

			if(degree[i]==1)//度为1的点

				sum++;

			//printf("%d\n",sum);

			printf("%d\n",(sum+1)/2);

	}

	return 0;

}


 


 

你可能感兴趣的:(poj)